I have a problem with this code:
ResultSet dane = statement.executeQuery("SELECT * FROM ProWarns WHERE blahblah = '" + cel + "'");
while (dane.next()) {
// some code (only get some string from result)
if (TimeEnd <= EndTime) {
statement.executeUpdate(
"DELETE FROM ProWarns WHERE id = '" + id + "'"); //and error
statement.executeUpdate(
"UPDATE ProWarnsPlayers SET num = '" + NewV + "'" WHERE Pl = '"+ tar + "'");
}
}
Error: java.sql.SQLException: Operation not allowed after ResultSet closed. Where is the bug and how can I fix it?
PS:
I am including a Pastebin of my DB class, in case its helpful.
A Statement object caches its result set, so when you execute the additional operations in your for loop the original result set gets 'reset'. Which leads to the error that is happening, when you call dane.next. From the Javadoc:
By default, only one ResultSet object per Statement object can be open
at the same time. Therefore, if the reading of one ResultSet object is
interleaved with the reading of another, each must have been generated
by different Statement objects. All execution methods in the Statement
interface implicitly close a statment's current ResultSet object if an
open one exists.
Options? Use another Statement object to execute the inner queries.
Related
I am using mySQL. As you see, the SQL statement is wrong at SELECT. So, I wonder what value the rs is?
I hope to get some advice. I thank you so much;
String sql = "SELCT * FROM user WHERE username = '" + username + "' and password = '" + password + "'";
ResultSet rs = stm.executeQuery(sql);
There would be no value because Statement.executeQuery(String) would throw a SQLException. As the linked Javadoc says,
Returns:
a ResultSet object that contains the data produced by the given query; never null
Throws:
SQLException - if a database access error occurs, this method is called on a closed Statement, the given SQL statement produces anything other than a single ResultSet object, the method is called on a PreparedStatement or CallableStatement
It will return you an exception having message like syntax error.
Easiest way to find is to debug your code by putting break points in code & examining / watching values of variables . Most IDEs have these debugging features. In addition to Elliott Frisch's answer, if I restructure your code like below then in case of invalid / incorrect SQL, control comes to catch block and you can see that value of rs remains null.
public void executeQuery(Connection conn, String username,String password) {
String sql = "SELCT * FROM user WHERE username = '" + username + "' and password = '" + password + "'";
ResultSet rs = null;
Statement stm = null;
try {
stm = conn.createStatement();
rs= stm.executeQuery(sql);
while(rs.next()) {
//Extract ResultSet here as per needed logic
}
} catch (SQLException e) {
// Your control comes here if query is wrong , put a break point at below line & examine value of rs
e.printStackTrace();
}finally {
// Close resources not needed after this method call like - result sets , statements & connection
}
}
Firstly statement won't execute, so next execution is depends on how you are going to handle that exception. So, if exception comes and if you handle also there will be null in ResultSet because no value assigned to it.
The problem occurs when executeQuery function runs, the sql statement is work correctly and gives correct results when it is runned on the sql editor. When it is runned on jdbc it is not executed. The connection accepts multi queries.
String query = "set #countOfLectureGrade = (SELECT Count(goc.Affect) FROM GradeOfCourse goc WHERE goc.LectureID = ?);"
+ "SELECT u.SchoolID, u.Name, u.Surname, u.Role, u.Email, "
+ "CASE WHEN #countOfLecture = 0 then 0 "
+ "ELSE AVG(0.01 * goc.Affect * gos.Grade) "
+ "END AS Average "
+ "FROM GradeOfCourse goc, GradeOfStudent gos, User u, CourseOfStudent cos "
+ "WHERE "
+ "(gos.CourseGradeID = goc.GradeID AND u.SchoolID = gos.StudentID AND goc.LectureID = ?) "
+ "OR (u.SchoolID = cos.SchoolID AND cos.LectureID = ? AND #countOfLectureGrade = 0) "
+ "GROUP BY u.SchoolID;";
try {
connection = super.getConnection();
PreparedStatement sqlStatement = connection.prepareStatement(query);
sqlStatement.setInt(1, lectureID);
sqlStatement.setInt(2, lectureID);
sqlStatement.setInt(3, lectureID);
ResultSet resultSet = sqlStatement.executeQuery();
java.sql.SQLException: ResultSet is from UPDATE. No Data.
This is not possible, you have to separate your queries, of for the best solution you can use procedures or function.
Procedure should take lectureID
Return your result, in your case it should multiples valus, you can read How to retrieve multiple rows from stored procedure in mysql? to know how to use procedure return multiple values
I am not familiar with JDBC but a quick search suggests you should use execute rather than executeQuery.
execute: Returns true if the first object that the query returns is a
ResultSet object. Use this method if the query could return one or
more ResultSet objects. Retrieve the ResultSet objects returned from
the query by repeatedly calling Statement.getResultSet.
https://docs.oracle.com/javase/tutorial/jdbc/basics/processingsqlstatements.html#executing_queries
Have a look at the following documentation which explains to use execute() instead of executeQuery() and then fire a getResultSet() on the Result set that you get.
The whole approach is to change your query into a Stored procedure and invoke the same through a CallableStatement.
Documentation suggests:
Although CallableStatement supports calling any of the Statement execute methods (executeUpdate(), executeQuery() or execute()), the most flexible method to call is execute(), as you do not need to know ahead of time if the stored procedure returns result sets.
Hope this helps!
I am creating a java program, with which I am editing into a Microsoft Access Database. I have a certain case, in which I need to search if a certain record already exists in my table, if it does, I want to update it, and if not, I want to create it from scratch.
I have found this piece of code:
IF EXISTS (SELECT * FROM USERS WHERE USERID=#UID) select 1 else select
This code gives me an error, saying that a SELECT, UPDATE or DELETE statement was expected.
In a code that I have tried my self, I have done the following:
try{
s = con.createStatement();
s.executeQuery("SELECT * FROM table WHERE date='" + today + "'");
rset = s.getResultSet();
if (rset.getString("date") == null){
s = con.createStatement();
s.executeUpdate("INSERT INTO table VALUES ('" + today + "','" + cflow + "','" + vat + "','" + cnn + "')");
}
}
catch (SQLException exp)
{
System.err.println(exp);
}
But with this code, when the record does not exist yet, the user input is not updated inside the database.
Thanks for your time :)
1st: If I can remember right, then is
IF EXISTS (SELECT * FROM USERS WHERE USERID=#UID) select 1 else select
an incomplete transact sql statement -used by the sql engine from a database system.
2nd:
if (rset.getString("date") == null){}
you should avoid this way, because there is a good chance to get a Nullpointer Exception.
In my eyes a better one is a test the size of resultset for zero or the resultset it self for the value of NULL.
In case the UPDATE statement won't also be executed, check your SELECT statement using the database engine -Ms Access, SQL Server, etc.- directly. The advantage is you can exclude a mistake in your SELECT query.
What about this?
SELECT IF EXISTS (SELECT * FROM USERS WHERE USERID=#UID) THEN 1 ELSE 0 END
or
SELECT IF(EXISTS (SELECT * FROM USERS WHERE USERID=#UID), 1, 0)
(I'm not sure about the real syntax here.)
(rset.getString("date") == null)
should be
(!rset.next())
rset is positioned 'before' the first result that gets returned. next() returns true if there was a 'next' result to get.
Also, what datatype is your 'date' variable? There's no guarantee that a date.toString() will format the date correctly for MS-Access version of SQL.
Rather, prepare a statement
PreparedStatement ps = connetion.prepareStatement("SELECT * from table where date=?");
and set the date like
ps.setDate(1, date);
then issue the query using the prepared statement.
That saves any toString() issues. (I haven't compiled this, it almost certainly won't work as-is, but the idea is there).
Here is what i used to find the last ID in a table. IF the table is empty the no ID will be returned. If table is populated then i needed the next ID for new record.
ResultSet mn = stmt.executeQuery("SELECT MAX(ExamID)FROM ExamResults");
if (mn == null){
jTextField1.setText("1");
} else{
while (mn.next()) {
int lastID =Integer.parseInt(""+(mn.getObject(1)));
jTextField1.setText(""+(lastID+1));
}
}
// close the objects
mn.close();
stmt.close();
conn.close();
I'm making a db call as follows:
String sqlAlert = "SELECT * FROM demotable where demo_no ='"
+rsDemo.getString("demo_no") + "'";
ResultSet rsAlert = db.GetSQL(sqlAlert);
if (rsAlert.next()) {
String newAlert = rsAlert.getString("cust3")+"1";
String newAlertSql = "UPDATE demotable SET cust3 = '" + newAlert + "' where demo_no='" + rsDemo.getString("demo_no") + "'";
System.out.println("Update alert msg: " + newAlertSql);
db.RunSQL(newAlertSql);
} else {
System.out.println("empty result. Demo_no = "+rsDemo.getString("demo_no"));
String sqlAlertinsert = "INSERT INTO demotable VALUES('" + rsDemo.getString("demo_no") + "','','','','','<unotes></unotes>')";
db.RunSQL(sqlAlertinsert);
System.out.println("insert demo done");
String sqlAlert2 = "SELECT * FROM demotable where demo_no ='"rsDemo.getString("demo_no") + "'";
ResultSet rsAlert2 = db.GetSQL(sqlAlert2);
if (rsAlert2.next()) {
String newAlert = rsAlert2.getString("cust3")+"1";
String newAlertSql = "UPDATE demotable SET cust3 = '" + newAlert+ "' where demo_no='" + rsDemo.getString("demo_no") + "'";
System.out.println("Update alert msg: " + newAlertSql);
db.RunSQL(newAlertSql);
}
rsAlert2.close();
}
rsAlert.close();
rs.close();
I am trying to insert rows into demographiccust if rsAlert returns an empty set and then access values from it. But my code returns this exception "Illegal operation on empty result set" around "if (rsAlert2.next()) { ". Why does it return an empty set even after inserting values into the table? Please help. Thank you.
It may be because of the open cursor. You must close your first Statement, prior trying the second. ResultSet is a connected thing, when you close the Statement it get closed too. I can't see the implementation of your db.RunSQL() and db.GetSQL() methods.
However, I am having the suggestion on how you should do it, in the first place. Here you go,
Update it without querying the database
Check how many rows updated. If none, then step 3, otherwise completed
Insert the record with the correct values in the first place. No need to update it after inserting.
Tips:
Try using PreparedStatement, instead
Try to stick with Java Naming Convention
Try using meaningful names, i.e. for example your method db.GetSQL() is not returning an SQL, but contrarily asking one, and in fact returning a ResultSet.
Never return a ResultSet. This may lead to bloated code and a lot of open cursors. Don't make the user of your method to close it. Close it yourself in your method where you are performing any database query, and return the result as a bean or a list of beans.
It's just a guess, but because you are interpolating rsDemo.getString("demo_no") directly into the SQL, you may be passing an SQL statement that isn't what you want. Try using the parameter binding api.
I connect to a DB2 database and makes the following query. I don't understand why I get the error: "invalid cursor state".
public static void blivPar() {
try {
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
stmt.setMaxRows(1000);
ResultSet drenge = stmt.executeQuery("SELECT * FROM People WHERE sex='M'");
ResultSet piger = stmt.executeQuery("SELECT * FROM People WHERE sex='F'");
drenge.first();
piger.first();
int i=0;
while(drenge.next()) {
while(piger.next()) {
i++;
System.out.print(i);
stmt.execute("INSERT INTO Couples Values ('"+drenge.getString(1) +
"','" + drenge.getString(2) +
"','" + piger.getString(1) +
"','" + piger.getString(2) + "')");
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
Thank you.
Found this on the JDBC Javadocs for the Statement interface: "The object used for executing a static SQL statement and returning the results it produces.
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists. "
see Statement javadoc
So it looks to me like you need two different Statements if you want two ResultSets open at the same time. Or you need to finish processing your first ResultSet and close it so you can re-use the Statement to create the second ResultSet.