ResultSet stuck looping on first row - java

I am doing a simple query which I know is good and syntactically correct (no exceptions caught on executing it and the ResultSet is returned).
However when I pass this result set to a method to loop through it and perform some operations, the program is stuck looping on the first row in this result set (infinite loop). I really can't figure out what this problem could be. If the query is good, the ResultSet has the right results (I can't see what's inside it via debug as such but it should be correct) so what can be the problem?
This is the code for a better picture of what I'm doing.
ResultSet rs3 = null;
if (linked == J.LINKED_TO_ORG) {
Vector<Integer> linkedTicketIds = new Vector<Integer>();
while (rs.next()){
// returns a set of id's for linked tickets
Vector<Integer> linkedToTicket = Ticket.get_linked_OrgTickets(con, rs.getInt(Ticket.FLD_ID));
if (!linkedToTicket.isEmpty()) {
// if there are linked tickets in the result set, add them to vector
// so they can be outputted alone
linkedTicketIds.add(rs.getInt(Ticket.FLD_ID));
}
}
if (!linkedTicketIds.isEmpty()){
rs3 = select_linked_or_unlinked(con, linkedTicketIds, select_from);
}
}
In select_linked_or_unlinked method the following query is built using a string buffer and the vector linkedTicketIds which returns good results as shown (formatting added to improve readability):
SELECT Tick.ID
, Tick.DESCRIPTION
, Tick.TICKETTYPE
, States.SHORT_NAME as state
, Pri.DESCRIPTION as priority
, Owners.Login as Owner
, Submitters.Login as Submitter
, types.SHORT_NAME as type
, Tick.TITLE
, Proj.Name as Project
, Proj.ID
, Tick.RELEASE_NUM as Release
, Tick.SUBMIT_DATE
, Tick.CUSTOMER
, rownumber() OVER (ORDER BY Pri.ZORDER DESC)
as ROW_NEXT
FROM HOBTRACK.Tickets_Customers_View Tick
, HOBTRACK.PROJECTS Proj
, HOBTRACK.PRIORITIES Pri
, HOBTRACK.STATES States
, HOBTRACK.USERS Owners
, HOBTRACK.USERS Submitters
, HOBTRACK.TICKETTYPES types
, HOBTRACK.SECURITY_LEVEL Security
WHERE Tick.ID IN (25031,25100,18123)
This is how the query is executed and returned:
Statement stmt = con.createStatement(); // where con is the connection
rs = stmt.executeQuery(above_query);
return rs;
Finally, the returned result set rs3 is passed to a method where while (rs.next()) is used to loop through this result set and perform operations. This is where the program gets stuck. Any Ideas on what can be the problem or how can I identify it?
Thanks for your help :)

Related

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.

Java statement.setFetchSize() works well when ResultSet size == Fetch size

I have a problem with retrieving data from Oracle database. I use ojdbc8 and my code is:
Statement stmt = conn.createStatement();
stmt.setFetchSize(20000);
ResultSet rs = stmt.execute(sql);
while(rs.next()) {
for(int i = 0; i < columnCounter; i++) {
logger.info(rs.getString(i) + " ");
}
}
What I don't understand here is that when my query returns let say 53000 rows all together then in while loop first 40000 rows are printed in console very quickly but then there is a huge 20-25 seconds break, nothing happens and after that the rest rows are printed. It is always like that. If my query returns 81000 rows then 80000 rows is printed very quickly then long brake and then missing 1000 rows.
So I don't know why but it looks like when in ResultSet I have exactly 20000 rows which is a fetch size then it goes well, but if the ResultSet has less than number set in FetchSize then it slow downs. Can anyone explain what is going on here and how to fix it to get rid of this huge gap/brake??

Order of columns returned in ResultSet

I have a Java program reading data from an Access database where the table is created dynamically each time, and the number of columns varies depending on the data populated.
The table has columns as shown below. Only columns RowID and StatusOfProcessing are fixed and will be at the end.
column1,column2,column3, ... columnN,RowID,StatusOfProcessing
Below is piece of code
String str = "SELECT TOP 50 * FROM Dynamic_table WHERE StatusOfProcessing='0'";
resultSet = stmt.executeQuery(str);
When reading data from the ResultSet, does it always have columns in the order listed above, or should I use
String str = "SELECT TOP 50 column1,column2,column3 .... columnN,RowID,StatusOfProcessing FROM Dynamic_table WHERE StatusOfProcessing='0'";
resultSet = stmt.executeQuery(str);
Can someone clarify?
SELECT * will normaly return columns in the order in which they were created, e.g., the order in which they appeared in the CREATE TABLE statement. However, bear in mind that in addition to retrieving the value of a column by its index, as in
int col1value = resultSet.getInt(1);
you can also retrieve the value in a given column by referring to its name, as in
int col1value = resultSet.getInt("column1");
Furthermore, if you need to see the actual order of the columns or verify the names and types of the columns in a ResultSet you can use a ResultSetMetaData object to get that information.

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}

how to mark a row as dead or used after using it in the java program

i have a table called user_request
req_id user_id name num_of_seats startplace
1 11 arjun 3 Mumbai
2 12 chethan 2 delhi
3 13 raj 4 pune
I have a java program that uses above details to schedule the seats which selects the first user_id on the table, so that the first request is performed,
stmt1 = conn.createStatement();
{
ResultSet rs1 = stmt
.executeQuery("SELECT num_of_seats FROM user_request ORDER BY req_id ASC LIMIT 1");
while (rs1.next()) {
size = rs1.getInt("num_of_seats");
System.out.println("the number of seats requested:-" + size);
}
//
code to perform scheduling using the details retrieved
//
now after this in the next run of the program I want the program to select the second row, so that the query should select the items from the second row and then the third, how can I do that??? I'm not getting a proper idea.. please help me...
the proper way to do it is to get everything out and then loop it within the java program.
The way you are doing it will put a lot more stress on the server/DB which under 99% of the case is MUCH slower than running some checking in the program itself.
try this
(sorry don't have an easy way to check my code, so it MIGHT have syntax error, but a least you'll get the idea)
stmt1 = conn.createStatement();
ResultSet rs1 = stmt.executeQuery("SELECT num_of_seats FROM user_request ORDER BY req_id");
int[] size = null;
if (rs1.next()) {
size = (int[])rs1.getArray("num_of_seats").getArray();
}
for(int i=0;i<size.length;i++){
System.out.println("the number of seats requested:-" +size[i]);
}

Categories