I'm trying to get a result set of a SQL query in a java class. The problem is that the first row of my table is never displayed on my UI. So I debugged it.
When the while loop is first executed, while(rs.next) line executes then it does not go in to the loop, return backs to the beginning of while loop and executes while(rs.next) line again, now it goes into the while loop and sets the result set.
But since it does not go into the loop in the first time, the first row of my table is not set into the result set.
I could not find the problem here.
I tried do{} while(rs.next) but some times it throws exhausted result set exception
String SQL_QUERY = select * from my_table;
Statement stt = null;
stt= conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet rs = stt.executeQuery(SQL_QUERY);
if (rs != null) {
rs.absolute(startRow); // I need to go to some specific row according to users request that is why I used this
}
while(rs.next){
// rs.getString...
}
Replace while to
do {
//old body here
} while (rs.next())
This construction check condition after execution of the body. Effectively skipping first next call.
You may want to check result of rs.absolute(startRow). If it false then result set contains less than startRow rows.
You are starting at startRow + 1 because you set rs.next after rs.absolute. Just change this and it will work.
String SQL_QUERY = select * from my_table;
Statement stt = null;
stt= conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet rs = stt.executeQuery(SQL_QUERY);
if (rs != null) {
rs.absolute(startRow); // here you are at row startRow
}
while(rs.next()){
// and here you are at row startRow + 1
}
I have a Stored Procedure that runs on MS SQL Server. It takes one parameter as input. Basically, it returns multiple rows.
I am calling the SP from my java application by using CallableStatement.
I would like to know if it possible to get the rows returned by the stored procedure in the form of ResultSet in my DAO layer?[like how we get a resultset when we do select * from EmployeeTable] . If yes, how do we do that?
P.S: I don’t have privilege to modify the stored procedure.
SQL Server knows two types of procedures returning results:
Batches
The procedure looks something like this:
CREATE PROCEDURE p_results(
#p_result_sets INT
)
AS
BEGIN
IF #p_result_sets = 1 BEGIN
SELECT 1 a;
END
ELSE IF #p_result_sets = 2 BEGIN
SELECT 1 a;
SELECT 1 b UNION SELECT 2 b;
END
END;
In this case, you don't know in advance what the result sets will look like, and how many of them you'll get. You will have to run the procedure using Statement.execute() as follows:
try (CallableStatement stmt = con.prepareCall("...")) {
boolean results = stmt.execute();
for (;;) {
if (results)
try (ResultSet rs = stmt.getResultSet()) {
// ... Fetch your results here
}
else if (stmt.getUpdateCount() != -1) {}
else
break;
results = stmt.getMoreResults();
}
// After all results are fetched, you can also retrieve OUT parameters, if applicable
}
Table-valued functions
The function looks something like this:
CREATE FUNCTION f_tables1 ()
RETURNS #out_table TABLE (
column_value INTEGER
)
AS
BEGIN
INSERT #out_table
VALUES (1)
RETURN
END
In this case, you don't really need a CallableStatement. An ordinary SELECT statement will do:
try (PreparedStatement stmt = con.prepareStatement("SELECT * FROM f_tables1()");
ResultSet rs = stmt.executeQuery()) {
// ... Fetch your results here
}
A stored Procedure is returning three Result sets.I want a value from of a column from the third result Set.I would like to loop through the result sets and get the value of that column.
Ex: lets say SP returns three tables.
table 1:
Sno,Col_val1,Col_Val 2
table2:
Sno,Col_val11,Col_Val 22
table 3:
Sno,Col_val111,Col_Val 222
the above are output of a SP.
i want the value of Col_val111.how to do the following in java?
This might help. The example was given here but reproduced below in case of link rot:
CallableStatement cstmt;
ResultSet rs;
int i;
String s;
...
cstmt.execute(); // Call the stored procedure
rs = cstmt.getResultSet(); // Get the first result set
while (rs.next()) { // Position the cursor
i = rs.getInt(1); // Retrieve current result set value
System.out.println("Value from first result set = " + i);
// Print the value
}
cstmt.getMoreResults(); // Point to the second result set
// and close the first result set
rs = cstmt.getResultSet(); // Get the second result set
while (rs.next()) { // Position the cursor
s = rs.getString(1); // Retrieve current result set value
System.out.println("Value from second result set = " + s);
// Print the value
}
rs.close(); // Close the result set
cstmt.close(); // Close the statement
You can get to the next result set using Statement.getMoreResults() and Statement.getResultSet.
Statement stmt = // prepare the statement
stmt.execute();
for (int i = 1; i < 3; i++) {
stmt.getMoreResults();
}
thirdResultset = stmt.getResultSet();
// process the third resultset
... plus a ton of code to check that all is going well.
This is the code which i made just for fetching the column value of the last table.Thanks nick and Jiri.
CallableStatement cal = null;
String sp_call = "{call "+SP_Name+" (?,?,?)" +"}";
cal= connection.prepareCall(sp_call);
cal.setString(1,param1);
cal.setInt(2,param2);
cal.setInt(3,param3);
ResultSet res =null;
cal.execute();
int rs_count = 0;
while(rs_count<3)
{
if(i<2){cal.getMoreResults();rs = cal.getResultSet();rs_count++;continue;}
else{return rs; }
}
In order to query the database meta data in Sybase ASE, I found this relevant answer (not the accepted one), to be ideal:
From a Sybase Database, how I can get table description ( field names and types)?
Unfortunately, I can't seem to find any documentation, how I'm supposed to call sp_help from JDBC. According to the documentation, sp_help returns several cursors / result sets. The first one contains information about the table itself, the second one about the columns, etc. When I do this:
PreparedStatement stmt = getConnection().prepareStatement("sp_help 't_language'");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getObject(1));
// ...
}
I only get the results from the first cursor. How to access the other ones?
When you have multiple result sets you need to use the execute() method rather than executeQuery().
Here's an example:
CallableStatement cstmt;
ResultSet rs;
int i;
String s;
...
cstmt.execute(); // Call the stored procedure 1
rs = cstmt.getResultSet(); // Get the first result set 2
while (rs.next()) { // Position the cursor 3
i = rs.getInt(1); // Retrieve current result set value
System.out.println("Value from first result set = " + i);
// Print the value
}
cstmt.getMoreResults(); // Point to the second result set 4a
// and close the first result set
rs = cstmt.getResultSet(); // Get the second result set 4b
while (rs.next()) { // Position the cursor 4c
s = rs.getString(1); // Retrieve current result set value
System.out.println("Value from second result set = " + s);
// Print the value
}
rs.close(); // Close the result set
cstmt.close(); // Close the statement
You also need to call getUpdateCount() as well as getMoreResults() to read the entire result set. Here is some code I used to call sp_helpartition to retrieve partition information from a SYBASE DB.
try {
connection = getPooledConnection(poolName);
statement = connection.createStatement();
CallableStatement callable = connection.prepareCall(
"{ call sp_helpartition(?) }");
callable.setString(1,tableName);
callable.execute();
int partitions = 0;
/*
* Loop through results until there are no more result sets or
* or update counts to read. The number of partitions is recorded
* in the number of rows in the second result set.
*/
for (int index = 0 ; ; index ++){
if (callable.getMoreResults()){
ResultSet results = callable.getResultSet();
int count = 0 ;
while (results.next()){
count++;
}
if (index == 1){
partitions = count;
}
} else if (callable.getUpdateCount() == -1){
break ;
}
}
return partitions ;
} catch (Exception e) {
return 0 ;
} finally {
statement.close();
connection.close();
}
Thanks to Martin Clayton's answer here, I could figure out how to query Sybase ASE's sp_help function generically. I documented some more details about how this can be done in my blog here. I worked support for multiple JDBC result sets into jOOQ. In the case of sp_help, calling that function using the jOOQ API might look like this:
Factory create = new ASEFactory(connection);
// Get a list of tables, a list of user types, etc
List<Result<Record>> tables = create.fetchMany("sp_help");
// Get some information about the my_table table, its
// columns, keys, indexes, etc
List<Result<Record>> results = create.fetchMany("sp_help 'my_table'");
Shouldn't this be a pretty straightforward operation? However, I see there's neither a size() nor length() method.
Do a SELECT COUNT(*) FROM ... query instead.
OR
int size =0;
if (rs != null)
{
rs.last(); // moves cursor to the last row
size = rs.getRow(); // get row id
}
In either of the case, you won't have to loop over the entire data.
ResultSet rs = ps.executeQuery();
int rowcount = 0;
if (rs.last()) {
rowcount = rs.getRow();
rs.beforeFirst(); // not rs.first() because the rs.next() below will move on, missing the first element
}
while (rs.next()) {
// do your standard per row stuff
}
Well, if you have a ResultSet of type ResultSet.TYPE_FORWARD_ONLY you want to keep it that way (and not to switch to a ResultSet.TYPE_SCROLL_INSENSITIVE or ResultSet.TYPE_SCROLL_INSENSITIVE in order to be able to use .last()).
I suggest a very nice and efficient hack, where you add a first bogus/phony row at the top containing the number of rows.
Example
Let's say your query is the following
select MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR
from MYTABLE
where ...blahblah...
and your output looks like
true 65537 "Hey" -32768 "The quick brown fox"
false 123456 "Sup" 300 "The lazy dog"
false -123123 "Yo" 0 "Go ahead and jump"
false 3 "EVH" 456 "Might as well jump"
...
[1000 total rows]
Simply refactor your code to something like this:
Statement s=myConnection.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
String from_where="FROM myTable WHERE ...blahblah... ";
//h4x
ResultSet rs=s.executeQuery("select count(*)as RECORDCOUNT,"
+ "cast(null as boolean)as MYBOOL,"
+ "cast(null as int)as MYINT,"
+ "cast(null as char(1))as MYCHAR,"
+ "cast(null as smallint)as MYSMALLINT,"
+ "cast(null as varchar(1))as MYVARCHAR "
+from_where
+"UNION ALL "//the "ALL" part prevents internal re-sorting to prevent duplicates (and we do not want that)
+"select cast(null as int)as RECORDCOUNT,"
+ "MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR "
+from_where);
Your query output will now be something like
1000 null null null null null
null true 65537 "Hey" -32768 "The quick brown fox"
null false 123456 "Sup" 300 "The lazy dog"
null false -123123 "Yo" 0 "Go ahead and jump"
null false 3 "EVH" 456 "Might as well jump"
...
[1001 total rows]
So you just have to
if(rs.next())
System.out.println("Recordcount: "+rs.getInt("RECORDCOUNT"));//hack: first record contains the record count
while(rs.next())
//do your stuff
int i = 0;
while(rs.next()) {
i++;
}
I got an exception when using rs.last()
if(rs.last()){
rowCount = rs.getRow();
rs.beforeFirst();
}
:
java.sql.SQLException: Invalid operation for forward only resultset
it's due to by default it is ResultSet.TYPE_FORWARD_ONLY, which means you can only use rs.next()
the solution is:
stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
[Speed consideration]
Lot of ppl here suggests ResultSet.last() but for that you would need to open connection as a ResultSet.TYPE_SCROLL_INSENSITIVE which for Derby embedded database is up to 10 times SLOWER than ResultSet.TYPE_FORWARD_ONLY.
According to my micro-tests for embedded Derby and H2 databases it is significantly faster to call SELECT COUNT(*) before your SELECT.
Here is in more detail my code and my benchmarks
The way of getting size of ResultSet, No need of using ArrayList etc
int size =0;
if (rs != null)
{
rs.beforeFirst();
rs.last();
size = rs.getRow();
}
Now You will get size, And if you want print the ResultSet, before printing use following line of code too,
rs.beforeFirst();
It is a simple way to do rows-count.
ResultSet rs = job.getSearchedResult(stmt);
int rsCount = 0;
//but notice that you'll only get correct ResultSet size after end of the while loop
while(rs.next())
{
//do your other per row stuff
rsCount = rsCount + 1;
}//end while
String sql = "select count(*) from message";
ps = cn.prepareStatement(sql);
rs = ps.executeQuery();
int rowCount = 0;
while(rs.next()) {
rowCount = Integer.parseInt(rs.getString("count(*)"));
System.out.println(Integer.parseInt(rs.getString("count(*)")));
}
System.out.println("Count : " + rowCount);
theStatement=theConnection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet theResult=theStatement.executeQuery(query);
//Get the size of the data returned
theResult.last();
int size = theResult.getRow() * theResult.getMetaData().getColumnCount();
theResult.beforeFirst();
I checked the runtime value of the ResultSet interface and found out it was pretty much a ResultSetImpl all the time. ResultSetImpl has a method called getUpdateCount() which returns the value you are looking for.
This code sample should suffice:
ResultSet resultSet = executeQuery(sqlQuery);
double rowCount = ((ResultSetImpl)resultSet).getUpdateCount()
I realize that downcasting is generally an unsafe procedure but this method hasn't yet failed me.
Today, I used this logic why I don't know getting the count of RS.
int chkSize = 0;
if (rs.next()) {
do { ..... blah blah
enter code here for each rs.
chkSize++;
} while (rs.next());
} else {
enter code here for rs size = 0
}
// good luck to u.
I was having the same problem. Using ResultSet.first() in this way just after the execution solved it:
if(rs.first()){
// Do your job
} else {
// No rows take some actions
}
Documentation (link):
boolean first()
throws SQLException
Moves the cursor to the first row in this ResultSet object.
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
Since:
1.2
Easiest approach, Run Count(*) query, do resultSet.next() to point to the first row and then just do resultSet.getString(1) to get the count. Code :
ResultSet rs = statement.executeQuery("Select Count(*) from your_db");
if(rs.next()) {
int count = rs.getString(1).toInt()
}
Give column a name..
String query = "SELECT COUNT(*) as count FROM
Reference that column from the ResultSet object into an int and do your logic from there..
PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, item.getProductId());
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
int count = resultSet.getInt("count");
if (count >= 1) {
System.out.println("Product ID already exists.");
} else {
System.out.println("New Product ID.");
}
}