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

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

Related

Sqlite Insert Runs Successfully But Does Have not any Effect On Database?

I am trying to add a single row to my table. It seems like it works just fine, but the row is not added to database. When i check the database there is no change on it.
I am trying to add it with insert method that SqliteDatabase provides with folowing code.
public void saveToCache(String word) {
ContentValues contentValues = new ContentValues();
contentValues.put("word", word);
long value = database.insert("CACHE",null, contentValues);
//The code below is for debug purposes, to see the if values are added
//But when executed it gives
//android.database.CursorIndexOutOfBoundsException: Index -1 requested,
//with a size of 13
Cursor cursor = database.rawQuery("SELECT * FROM CACHE",null);
for(int i=0; i< cursor.getCount();i++){
String a = cursor.getString(0); //This is where the exception above happens
}
}
The value attribute seems right, everytime I use the function, it increments by 1. But the rawQuery method below gives the error I have provided in the comment.
p.s : The table "CACHE" has only one COLUMN called word.
You need to change the loop that accesses the rows returned to the cursor:
Cursor cursor = database.rawQuery("SELECT * FROM CACHE",null);
while (cursor.moveToNext()) {
String a = cursor.getString(0);
// do something
}
After the call to rawQuery() the cursor's index is before the 1st row (if it exists).
The cursor does not advance to the first or to the next row without a call to moveToFirst() or moveToNext().

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

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.

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.

Returning a single column value from SQL database

I need to get the latest entry from my database, but not the autoincrement.
This function is in my databasehandler:
public int getLatestRouteNumber()
{
int number = 0;
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT MAX("+ KEY_ROUTENUMBER + ") FROM " + TABLE_LOCATIONS;
Cursor c = db.rawQuery(query, null);
if (c.moveToFirst() && c != null) {
number = c.getInt(3);
}
return number;
}
it craches at the line where "number = c.getInt(3).
The third column in my database exists and has data in it.
The error I'm gettin is "Couldn't read row 0, col 3 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it." I only need one value in the entire database, not even an entire row.
You have only one column in cursor but trying to get value of 3rd column... Tat is the error
Change it to getInt(0);
The returned result-set has nothing to do with table columns in your case. You should use
number = c.getInt(0);
Your resultset contains just one column and one row, basically a scalar value, it doesn't matter how many columns you have in your table, what you should consider here is the value you obtain from your query In your case just one value. Use
getInt(0)
have you tried something like this :
String query = "SELECT MAX("+ KEY_ROUTENUMBER + ") as my_max FROM " + TABLE_LOCATIONS;
And :
columnIndex = c.getColumnIndexOrThrow("my_max");
number = c.getInt(columnIndex );
That's better than using indexes, indexes may be wrong if the raw query changes.
getInt (3) returns the value of the 3rd column returned by the query. Your query only had 1 column.
Change getInt (3) to getInt (0)
"c.getInt(3);" does not get the value from the column in your table, it gets it from the column in your cursor.
And you only selected one column into your cursor.
So I believe it should be "c.getInt(1);"

Categories