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.
Related
I have been working with a JDBC for the past couple of weeks and I have come upon a problem that I figure will have subjective answers. Let's suppose we want to create a method that dynamically constructs a SQL statement that is to be executed based upon what a user inputs into some GUI. Based on what the user has put into the GUI, we need to gather that information, validate it, then pass it into the database. That is, if the user has left any field empty, we simply do not add any extra conditionals to the SQL statement.
For example if the user left the hypothetical column "name" blank (and the table automatically generates primary keys) we might write
INSERT INTO <tableName>;
to add a new row to the table.
Alternatively if the user has given a name, we write,
INSERT INTO <tableName> (name) VALUES (?);
.
With that context given lets suppose I construct a method that dynamically creates this SQL statement:
public void addToDatabase(){
Connection connection = createConnectionToDatabase();
String str = "INSERT INTO <tableName>";
if(!name.isBlank()){
str += " (name) VALUES (?)"
}
str += ";";
PreparedStatement statement = connection.prepareStatement(str);
if(!name.isBlank()){
statement.setString(1, name);
}
statement.execute();
connection.close();
If you notice, we check if name is blank twice - which I find rather annoying since it should only be checked once in my opinion. The first time we check if name is blank is to construct the proper string to be placed into the SQL statement. The second time we check if the name is blank is to confirm if we need to pass the parameter into the prepared statement. This creates a sort of catch-22 that forces us to check if the name is blank twice which I do not like. Are there any better ways of handling this situation to only have to check for the name once?
I found a few other answers stating that there is no better way of doing this kind of dyamic SQL statements but I don't like that answer and am hoping for a better one. Thanks.
what you want is equivalent to
String str = "INSERT INTO <tableName> name values (?)";
PreparedStatement statement = connection.prepareStatement(str);
if(!name.isBlank()){
statement.setString(1, name);
}
else {
statement.setNull(1, Types.VARCHAR);
}
Here is my code. I am trying to use a variable instead of a column name in here
But I get below exception. How can I resolve this error?
You can't bind table/column names in a prepared statement, nor would you normally want to allow this. Here is a working version of your code:
String query = "UPDATE report SET itemno = ?";
pst = (PreparedStatement) con.prepareStatement(query);
pst.setInt(1, dqty);
pst.executeUpdate();
Notes:
You almost certainly want to add a WHERE clause to your update, without which it would affect every record in the table. With prepared statements, you don't need to worry about escaping your literal data. Just let Java handle this for you.
If you really need the ability to update other table/column combinations, then just create other statements for that. One size fits all works at 7-Eleven, but not JDBC, since you might SQL injected.
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.
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.
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.