Why is "while (rs.next())" necessary here? - java

I want to select the maximum line number from my database "Logs" and store it in a variable m.
Here's my code:
ResultSet rs = stmt.executeQuery("Select max(Line) as L from logs");
while (rs.next()) { // Why do I need this
int m = rs.getInt("L");
System.out.println(m);
}
But it doesn't work unless I use while(rs.next()).
If I understand correctly, rs.next() moves the cursor to the next row, but here, in this result, I only have one row.
So, can someone explain why the loop is necessary? The only thing I can think of is that the first cursor is set on the column name, am I right?

Why?
The cursor is initially placed before the first element. You need to advance it once to access the first element.
This was obviously done because traversing the results using a loop is very convenient then, as you see. From the official documentation:
Moves the cursor forward one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.
Solution
So, while you don't need any loop, you need to advance the cursor once. A single rs.next(); would technically be enough:
rs.next();
// Access the result
However, you probably want to account for the case where there was no match at all, since:
When a call to the next method returns false, the cursor is positioned after the last row. Any invocation of a ResultSet method which requires a current row will result in a SQLException being thrown.
So the code would fail in this case.
Because of that, you should account for the case and use the returned boolean to guard your access:
if (rs.next()) {
// Access result ...
} else {
// No match ...
}

From the official documentation (which you should have read btw):
Initially the cursor is positioned before the first row. The next method moves the cursor to the next row, and because it returns false when there are no more rows in the ResultSet object, it can be used in a while loop to iterate through the result set.
You basically need to move it, in your case moving it once is enough:
rs.next();
System.out.println(rs.getInt("L"));

You can convert this to use a simple if statement instead.
if(rs.next()) {
// other code here
}
You would use while when you have more than one row to bring back.

A ResultSet cursor is initially positioned before the first row, the
first call to the method next makes the first row the current row, the
second call makes the second row the current row, and so on.
consider you have something like this.
->1->2->3
^
your "rs" is initially pointed before 1, when you call rs.next() it advances the arrow to point to 1
->1->2->3
^
so if you do not call the next() method then you do not get the result.
Hope this helps

There are different types of Executing the Commands. Cursors are used to read the data from your executed queries. When you execute to Read, you using Forward Only Cursor by default hence you are only getting next result after calling Recorset.Next() ! I don't want to go in much deeper here. You can read about cursors here : https://learn.microsoft.com/en-us/sql/ado/guide/data/types-of-cursors-ado?view=sql-server-2017
The best solution in your case is to use Scalar Resultset which will return only ONE CELL thats exactly what you want to implement without having to loop through your result set. Following example shows how you can implement such :
using System;
using System.Data;
using System.Data.SqlClient;
class ExecuteScalar
{
public static void Main()
{
SqlConnection mySqlConnection =new SqlConnection("server=(local)\\SQLEXPRESS;database=MyDatabase;Integrated Security=SSPI;");
SqlCommand mySqlCommand = mySqlConnection.CreateCommand();
mySqlCommand.CommandText ="SELECT COUNT(*) FROM Employee";
mySqlConnection.Open();
int returnValue = (int) mySqlCommand.ExecuteScalar();
Console.WriteLine("mySqlCommand.ExecuteScalar() = " + returnValue);
mySqlConnection.Close();
}
}
We are using ExecuteScalar to return only ONE Cell. Remember, Even if your Query returns Multiple Rows/Columns, this will only returns VERY FIRST CELL always.

Related

Get RowCount from a ResultSet after a few next() calls

I have the following code:
//rs is a ResultSet from a prepared statement
rs.last();
this.resultCount = rs.getRow();
rs.beforeFirst();
If I execute that code after i executed a few rs.next(), then the rs.beforeFirst() is wrong.
So my question is: how can I get back to the current position and not to the beforeFirst position?
Question: "how can I get back to the current position and not to the before the first position."
Answer: You can use resultSet.absolute(rowIndex);
Detailed explanation:
Moves the cursor to the given row number in this ResultSet object.
If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second row 2, and so on.
If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.
If the row number specified is zero, the cursor is moved to before the first row.
However, you can use absolumte(rowIndex) in your program such as,
int currRowIndex = resultSet.getRow();
resultSet.last(); // <- can throw if resultSet type is TYPE_FORWARD_ONLY
this.resultCount = resultSet.getRow();
resultSet.absolute(currRowIndex); // <- It will allow you to set cursor position.
Warning: When the use of last() it can throw if the resultSet type is TYPE_FORWARD_ONLY.
last
boolean last() throws SQLException
Moves the cursor to the last row in this ResultSet object.<be>
Returns:
- true if the cursor is on a valid row;
- false if there are no rows in the result set
Throws:
- SQLException: if a database access error occurs; this method is called on a closed result set or the result set type is TYPE_FORWARD_ONLY
- SQLFeatureNotSupportedException: if the JDBC driver does not support
this method

resultSet.next() coming 'false' even though it is executed as true in previous statement

I'm trying to execute a query and store the result in the result set named 'objRs'.
In evaluating an if statement, 'objRs' is evaluated as 'true', and the code withing if the if block gets executed.
But in the statement below it, 'objRs' is coming as 'false'.
See the below code for a clearer picture:
if (objRs!= null && objRs.next()) //the statements in this block is //executed
{
user_Name = objRs.getString("login_name");
user_id = objRs.getString("user_id");
corp_id = objRs.getString("corp_id");
corp_grp_id = objRs.getString("corporate_group");
f_name = objRs.getString("first_name");
l_name = objRs.getString("last_name");
moNumber = objRs.getString("cont_mobile");
gender = objRs.getString("gender");
address = objRs.getString("address");
city = objRs.getString("b_adr1_city");
state = objRs.getString("b_adr1_state");
country = objRs.getString("b_adr1_country");
}
}
#SuppressWarnings("unused")
Boolean test = objRs.next(); //the value of test is showing //as 'false' while debugging.
The above code is part of a 'try' block.
Please suggest a solution such that the 'objRs' doesn't become 'false' in the above case.
As per ResultSet.next() each call to this method moves to the next record in the result set until false is returned indicating that there are no more results.
Moves the cursor froward one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.
If you want to test var have value of your objRs.next() call in if just do the following
Boolean test;
if (objRs!= null && test=objRs.next())
{
...
}

Failure to enter the while loop even when the condition is true

I am working to extract the data from database. Please find the code below:
I am using "org.springframework.jdbc.support.rowset.SqlRowSet" from Springframework.jdbc.
String query="SELECT * from TABLE_NAME where id=? and password=?";
args.add(userId);
args.add(password);
SqlRowSet rs = this.jdbcTemplate.queryForRowSet(query, args.toArray());
while (rs.next()) {
---Some Code---
}
rs.next() is true, but it is not going into the loop. Need some help on how to overcome this issue. Any help is appreciated.
This is just a guess, but since you know that rs.next() returns true, it means you executed it (either in debug mode or printed to console or whatever).
Every time you execute it, it advances the rowset to the next row, if there is one. If your rowset contains only 1 row, and you "check" the value returned by rs.next() before the loop, the loop will never be entered because when it's called again there are no more rows, so it returns false.
I don't the reason for that. But I have changed the implementation. I have changed the while loop to for loop by getting the size from the resultSet. Thanks a lot for your suggestions.
int size =0;
if (rs != null)
{
rs.beforeFirst();
rs.last();
size = rs.getRow();
}
for (int i =0;i<size;i++){//Do SOMETHING}

Cursor isAfterLast() returns true when reaching last row

I wanted to iterate over a cursor over a table with 2 rows of data. My first try was:
c.moveToFirst();
while(!c.isAfterLast()){
//this code runs once
c.moveToNext();
}
However after debugging I noticed that I am missing the last row of my data. And that was because the while loop ends when the mPos variable becomes equal to mCount in the counter. After replacing the above code with the one below the problem was solved:
c.moveToFirst();
do{
//this code runs twice
}while(c.moveToNext())
Essentially in the first method, the while loop runs 1 time less than the second one. Isn't isAfterLast supposed to return true only after the cursor passes the last row?
Note that moveToNext() returns a boolean signifying that there is a next (true), but ALSO, if true - it moves the cursor. So that in this case when you return to evaluate while(!c.isAfterLast()) after c.moveToNext(); you are already at the last item (and so the cursor is pointing to the position after the last row.
If your goal is to iterate through the cursor, then you can just do this:
while (c.moveToNext()) {
//do whatever with your data - like
//String value = c.getString(c.getColumnIndex("SOME_COLUMN_NAME"));
}
You can look at the related discussion here.

Access String Array outside of two loops

I have an array of Strings created inside of a while loop nested inside a for loop. This has to do with creating an array from a column of strings in Derby but I will leave out some stuff for simplicity's sake.
The reason I am not providing the full code is because the problem is very specific. I am having no problems whatsoever with my database, resultset, statements, or queries. It's just accessing the array outside of the two loops.
//in the class,
private int rowCount; //Count of the rows in my column of strings
public String stringArray[];
//in the method I am using
public void myMethod() {
rowCount = 4; //In my code it actually counts it, lets say its four though.
stringArray = new stringArray[rowCount]; //set
for (int i = 0; i < rowCount; i++) {
while (rs.next()/*rs is simply a result set of a statement executeQuery to select the correct table*/)
{
stringArray[i] = rs.getString(2); //2 is the column number in the table
}
}
//Need to access stringArray here. When I try to print out values, it always prints out as null.
}
Thanks!
There's something wrong with your nested loops. For each row (each value of i / each execution of the outer loop), you iterate through your whole result set and overwrite stringArray[i] (i not chaning) many times.
When you get to the second row (i.e. i is 1 or higher), rs.next() will already be false, since you tranversed the whole rs in the first iteration of the outer loop.
Maybe you just need to replace your inner loop while(rs.next()) with a single call to rs.next()
Perhaps in your actual code, where you say:
rowCount = 4; //In my code it actually counts it, lets say its four though.
you are performing the count of the rows by doing something like:
for( rowCount = 0; rs.next(); rowCount++ ) { }
If you're doing something like that, then you've basically read all the rows already during the counting phase, and when you try to re-process the rows later the rs.next() method simply returns false since it's already read all the rows.
Of course, I'm just guessing...

Categories