jdbc - Multiple select statements in one query [duplicate] - java

This question already has answers here:
How to create temporary procedures in MySQL?
(3 answers)
Closed 6 years ago.
Firstly, I want to say that this question is not about JOIN or UNION.
Also, there are some answers on stack overflow which I've tried, but I'm still having issues. (example: Multiple queries executed in java in single statement)
Problem:
I want to retrieve data from two tables which I can't do using JOIN or UNION since they contain different types of data and I'm after different number of rows from each table. The reason why I want to do it in one go is efficiency however if somebody is able to convince me that two calls instead of one make almost no difference in overhead then I'll happily solve my problem like that (although it would still be nice to know how to use one query only)
Code:
Based on this, I wrote the following code (excerpt):
String sql = "SET #organizationId = 0;" +
"SELECT #organizationId := Id 'Id', Name FROM Organization WHERE Id = ?;" +
"SELECT AssociatedOrganizationId FROM OrganizationAssociations WHERE OrganizationId = #organizationId;";
Connection conn = null;
try {
conn = dataSource.getConnection();
CallableStatement cs = conn.prepareCall(sql);
cs.setInt(1, organizationId);
boolean isResultSet = cs.execute();
if (!isResultSet) {
logger.error("getOrganization - retrieved result is not a ResultSet");
}
OrganizationDto organization = null;
ResultSet rs = cs.getResultSet();
if (rs.next()) {
// create organization object using retrieved data
}
rs.close();
Behaviour causing the issue:
cs.execute() always returns false.
Observations and actions I took to try to resolve the issue:
As stated here and in Java documentation, CallableStatement was designed to be used for calling stored procedures. Stored procedures themselves never return a value and this can only be achieved through OUT parameters.
Bearing that in mind, it doesn't surprise me that .execute() returns false.
I have however changed CallableStatement to PreparedStatement and Statement but that didn't change much in terms of the outcome (cs.getResultSet() still returned null)
The answers I'm seeking:
1. I'd like to know how can I achieve retrieving data from multiple tables using one query with multiple SELECT statements in jdbc. That is to be achieved without JOINS, UNIONS etc. I'd like to be able to use the query I already have if possible (query works perfectly fine - tested in HeidiSQL).
2. (Optional) If there's anybody out there who thinks that two queries would make not much difference in terms of database load and performance then I'd like to be convinced that this actually is the case.
Update #1:
To clarify, this is the data that my query returns:
ResultSet #1:
Id, Name
1, "org1_name"
ResultSet #2:
AssociatedOrganizationId
2
3

First, your two queries can be written as a single query using a join:
SELECT AssociatedOrganizationId
FROM OrganizationAssociations oi JOIN
Organization o
ON oa.OrganizationId = o.id
WHERE o.id = ?
Second, this is not even needed, because you can simplify the whole thing to:
SELECT AssociatedOrganizationId
FROM OrganizationAssociations oi
WHERE oa.OrganizationId = ?
I would suggest that you take some time out to study SQL and learn how databases work. It would probably greatly help you with the problems you want to solve.

Related

SQLServer - Is it possible to update a geometry column using a jdbc resultset?

Is it possible to update a geometry column in a SQLServer database using a "updatable" jdbc resultset?
I've tried both the updateString() and updateObject() methods to no avail. For example:
String point = "geometry::STGeomFromText('POINT (30 -20)',4326)";
rs.updateString("COORDINATE", point);
rs.update();
Throws exception:
com.microsoft.sqlserver.jdbc.SQLServerException: The string is not in a valid hex format.
I haven't been able to find what this error means. Do I need to escape certain characters? Am I allowed to pass a function as a string? Or should I use a different update method like updateBlob() or updateNCharacterStream()?
BTW, I can update the geometry using a prepared statement but I prefer not to. Example:
String sql = "UPDATE MY_TABLE SET COORDINATE=geometry::STGeomFromText(?,4326) WHERE ID=?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, "POINT (30 -20)");
Again, I don't want to use prepared statements. I would like to update records using the resultset (e.g. updateString).
Your current code is the equivalent of trying to set the value of the column to the string "geometry::STGeomFromText('POINT (30 -20)',4326)" which obviously doesn't work as a string value of a function call is not the same as a function call itself. UpdateString can only be used to set a value, not call a function.
Based on the error message, you need to use a hex string with the already encoded coordinate. I don't know if there is a method available in Java to calculate this, so I fear your existing workaround using UPDATE might be the only solution available to you.

If exist return id else insert in postgres [duplicate]

This question already has answers here:
Insert, on duplicate update in PostgreSQL?
(18 answers)
Closed 9 years ago.
I am new to postgres and i'm am having to populate a database using it. I cant submit my actual code for reference but my program is in java and i'm trying to do something along these lines.
IF EXISTS (SELECT 1 FROM TEST WHERE FOO = 2 and BAR = 3)
BEGIN
SELECT TableID FROM TEST WHERE FOO = 2 and BAR = 3
END
ELSE
BEGIN
INSERT INTO TEST(FOO, BAR) VALUES(2, 3)
END
I'm trying to do something along these lines because my program is just parsing a bunch of files and populating the database. I need to ensure that if someone goes back and runs the program again on the same files that the database wont contain duplicate entries. The id associated with this insert/record found is used to populate a linking table. I found this example on another stackoverflow questions only it relates to Microsoft SQL Server 2005. I'm using postgres and it fails on the very first line at IF. I understand different database languages operate slightly different. Is there a way to do an IF EXISTS return ID else insert using postgres.
Currently i'm checking if the entry exist and if it doesnt insert. But then i'm having to query the database again to get the id of the record had it existed.
int id = 0;
PrepareStatement ps = conn.prepare(SQL command, statement.generatekeys); //syntax is not correct for the preparestatement but i'm not looking at my code and dont remember it off top of my head.
ResultSet rs = ps.executeUpdate();
if(rs.next()){
if(rs.getGeneratedKeys().rows() > 0) //not sitting at my code but there is a way to check if a key was generated from an insert
id = rs.getGeneratedKeys()
}else{
id = rs.getInt(1);
}
}
Update Taken from comments:
The better questions is Is there a way to do an if exist return id else insert without querying/checking a where clause twice.
I want to avoid doing a WHERE check twice to get either my id from existing data or from the new entry. My condition checks are rather lengthy as some of my tables contain upwards of 14 attributes. Currently what i do is query the database once doing an INSERT if doesn't exist. If my getGeneratedKeys().size() = 0 i know the INSERT failed because it exist and then I re-query the database with the same where clause from my original query and grab the id.
This is closely related to an UPSERT or MERGE operation, which isn't supported directly by PostgreSQL. Upsert is rather more complicated in a concurrent environment than you'd expect.
Most of the concurrency problems with upsert also apply to what you want to do. Your current code is entirely wrong in the presence of more than one thread doing updates at a time.
Read depesz's article on the topic then search Stack Overflow for [postgresql] upsert or [postgresql] merge, and this SO post I wrote.
You should be able to fairly easily adapt the PL/PgSQL function given there to do the job. It'll only run correctly in READ COMMITTED isolation, though.

What does "=?" represent when used in an SQL query

I'm fairly new to SQL and I'm currently reworking a java program that another
programmer has developed. When I print one of his query select statements the script contains sql syntax:
SELECT * from database WHERE id = ?
I just want know what =? is supposed to do? I've been googling around and I can't find any relevant answer.
It's not a SQL notation, but a JDBC (Java Database Connectivity) notation. The ? gets replaced with a parameter that is specified separately. Using this approach, instead of trying to substitute the parameter yourself into the string, helps prevent the risk of SQL injection.
The ? is a place holder, a parameter, so that you can pass it in dynamically and return different results for different parameters.
Somewhere in the code you should see that he adds the parameter to the Statement object and execute it.
Most likely you are using a tool that will replace the "?" with an actual value. I've seen this in other tools before such as SQL DTS (Data Transformation Services)... but that's showing how old I am :)
The ? is not part of the SQL language.
The ? is a place holder used in SQL queries when used with JDBC Prepared statement. Using a prepared statement has advantages over the normal statement specially when you use it repeatedly (say in a loop).
Here is an example :
PreparedStatement ps =
connection.prepareStatement("select name from users where user_name = ?");
ps.setString(1, "user1");
the "?" gets replace by "user1" when the query is run and the first name of the user with user name "user1" is returned.

Open two resultsets simultaneously

I am trying to do this:
while (rs.next()) {
int id = rs.getInt(1);
ResultSet innerRs = stmt.executeQuery("select something from sometable where id =" + id + ";");
String one = innerRs.getString(1);
String two = rs.getString(2); //result set is already closed thrown here.
}
but I am getting the error "result set already closed". I am using Postgresql. I can't really figure out another way to do this that isn't very labour intensive. How can I get around this error?
You don't need two resultsets. Just learn the SQL JOIN clause so that you can get the desired data from two different tables in a single SQL query.
If you really need to, then creating a separate statement instead of reusing an existing one is indeed the way to go. Reusing it would namely force all previously opened cursors (resultsets) to be closed.
You use stmt.executeQuery(), did you use stmt to execute rs? If so, you need a new statement as creating a query on one you used already forces it to close, resulting in this error.

Does the preparedStatement avoid SQL injection? [duplicate]

This question already has answers here:
How does a PreparedStatement avoid or prevent SQL injection?
(10 answers)
Closed 5 years ago.
I have read and tried to inject vulnerable sql queries to my application. It is not safe enough. I am simply using the Statement Connection for database validations and other insertion operations.
Is the preparedStatements safe? and moreover will there be any problem with this statement too?
Using string concatenation for constructing your query from arbitrary input will not make PreparedStatement safe. Take a look at this example:
preparedStatement = "SELECT * FROM users WHERE name = '" + userName + "';";
If somebody puts
' or '1'='1
as userName, your PreparedStatement will be vulnerable to SQL injection, since that query will be executed on database as
SELECT * FROM users WHERE name = '' OR '1'='1';
So, if you use
preparedStatement = "SELECT * FROM users WHERE name = ?";
preparedStatement.setString(1, userName);
you will be safe.
Some of this code taken from this Wikipedia article.
The prepared statement, if used properly, does protect against SQL injection. But please post a code example to your question, so we can see if you are using it properly.
Well simply using PreparedStatement doesn't make you safe. You have to use parameters in your SQL query which is possible with PreparedStatement. Look here for more information.
The PreparedStatement alone does not help you if you are still concatenating Strings.
For instance, one rogue attacker can still do the following:
call a sleep function so that all your database connections will be busy, therefore making your application unavailable
extracting sensitive data from the DB
bypassing the user authentication
And it's not just SQL that can b affected. Even JPQL can be compromised if you are not using bind parameters.
Bottom line, you should never use string concatenation when building SQL statements. Use a dedicated API for that purpose:
JPA Criteria API
jOOQ

Categories