java.sql.SQLException:[Microsoft][ODBC Driver Manager] Invalid descriptor index - java

I use the following code
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:access");
String sql = "Select * from table";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery( sql );
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
for (int i = 1; i <= columns; i++) {
columnNames.addElement( md.getColumnName(i) );
}
while (rs.next()) {
Vector row = new Vector(columns);
for (int i = 1; i <= columns; i++){
row.addElement( rs.getObject(i) );
}
data.addElement( row );
}
rs.close();
stmt.close();
}catch(Exception e){
System.out.println(e);
}
It displays:
java.sql.SQLException:[Microsoft][ODBC Driver Manager] Invalid descriptor index
How is this caused and how can I solve it?

I have had the same exact error, this out of an ODBC Express Driver for Delphi.
The solution I have found is:
Place your varchar(max) and or varbinary(max) fields at the end of your select Query. (Order in the table definition doesn't matter).
This really fixed it for us, thought to share it with you guys.

I doubt the exception is thrown by one of the lines in the posted code. I have my reasons to state so.
A SQLException with the message "Invalid descriptor index" is usually obtained when you read the result set incorrectly. There are various ways in which this scenario can manifest:
Reading columns out of sequence. I'm afraid, some JDBC drivers will require you to read columns in order, starting at the first column. That's the way some drivers have been written; you cannot skip any columns when reading the resulting result set, as the drivers are actually reading a stream and converting objects in the stream to objects of the JDBC types.
You might be reading a column, whose index is invalid, or whose column name doesn't match any of the returned columns in the result set. The simple resolution is to either fix the query to return the needed column, or fix your code to not read the absent column.
If you need to solve it, you need to know which one of the above conditions is true in your code, and rectify accordingly.

I know this bug for many years by using ODBC driver with PHP. Try to place your text and image columns at the end of select list.Dont use
select * from t
but enumerate rigidly
select plain_column1, plain_column2, .... image_column from t
Unfortunately Microsoft doesn't get tired by fixing the bug. JDBC driver works OK.

That will occur if you're trying to get the resultset variable value in the index value of 0.
For example:
Consider a table which has 5 columns:
ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName);
while(rs.next())
{
for(int i=0;i<5;i++)
//This will throw the exception
System.out.println(rs.getString(i)); //Since the value will be returned from 1 not 0
//The below code was the right way
System.out.println(rs.getString(i+1));
}

I got an error
SEVERE: null
java.sql.SQLException: [Microsoft][SQL Server Native Client 10.0]Invalid Descriptor Index
code was
String sqlStr = "select soldItems.payment as aa, Sysuser.name as sname, Books.Name as abookName, soldItems.Qunt as qunt, soldItems.date as soldBooks from Sysuser inner join soldItems on soldItems.CustomerId=Sysuser.id inner join Books on Books.bookId=soldItems.bookId where CustomerId='" + cusId + "' and PaymentDone is NULL";
System.out.println(sqlStr);
DbConnection con = new DbConnection();
con.getConnection();
ResultSet rs = con.getData(sqlStr);
while (rs.next()) {
int i = 0;
dataArry[i][0] = rs.getString("abookName");
dataArry[i][1] = rs.getString("qunt");
dataArry[i][2] = rs.getString("aa");
dataArry[i][3] = rs.getString("soldBooks");
i++;
}
the fix is rs.getString needs to be in the same order of the SQL
so the code needs to be
dataArry[i][2] = rs.getString("aa");
dataArry[i][0] = rs.getString("abookName");
dataArry[i][1] = rs.getString("qunt");
dataArry[i][3] = rs.getString("soldBooks");

I have explained #Remco answer with example which is simple and short and helped me to solve my problem. Find the column info of MYTABLE first and place the column at the end with max values(suppose varchar(max) and or varbinary(max)). Try the example below.
With Error
library(DBI)
library(ODBC)
myquery<- dbGetQuery(con,"SELECT * FROM MYTABLE")
Error in Result_fetch....: Invalid Descriptor Index
Solution
dbcolumnInfo(dbSendWuery(con,"SELECT * FROM MYTABLE")
From the results for DateTimeSampled is varchar(max). Place this column at the end of MYTABLE using following query.
myquery<- dbGetQuery(con,"SELECT [PROCHI],[hb_extract],
[QuantityValue],[QuantityUnit],[Interpretation],
[LabNumber],[LocalClinicalCodeValue],[DateTimeSampled]
FROM MYTABLE")
Enjoy SQL with R

Related

SQL Sum Query works in PHPmyAdmin, but not in Java resutset

I have a table called "Transactions". It has 5 attributes: Date, Description, Amount, Clientname, Transaction_ID where Transaction_ID is the primary key. In the example Data, the Clientname, "John Smith" has two transactions where he spend 100.10 and 56.56 each. The SQL Query returns the expected result of 156.66 in PHPMyAdmin, but JDBC doesn't seem to recognize it in the ResultSet.
Here is my code:
public void calculate_client_spending() throws SQLException {
ConnectionClass Databaseloader = new ConnectionClass();
Databaseloader.getConnection();
String sql = "SELECT SUM(Amount) AS total FROM Transactions WHERE Clientname = 'John Smith';";
ResultSet rs = Databaseloader.executeSQLRequestCommand(sql);
// rs.next();
// System.out.println(sum);
ResultSetMetaData rsMetaData = rs.getMetaData();
int numberOfColumns = rsMetaData.getColumnCount();
System.out.println(numberOfColumns);
// get the column names; column indexes start from 1
for (int i = 1; i < numberOfColumns + 1; i++) {
String columnName = rsMetaData.getColumnName(i);
// Get the name of the column's table name
if ("total".equals(columnName)) {
System.out.println("Bingo!");
rs.last();
int count = rs.getRow();
rs.beforeFirst();
System.out.println(count);
while (rs.next()) {
Results_trasactions.setText("");
System.out.println("The total profits today are: " + rs.getString(1));
}
}
}
}
This Query returns null in this example, but if I did rs.getDouble(1), it would return 0. Any idea what the issue may be here? I am able to get similar SUM Query's to work, such as a SUM for all clients and the WHERE clause seems to work for my primary key, but this specific Query JDBC doesn't seem to like it even though the SQL is valid in PHPmyadmin which makes me want to believe that it is a Java issue and not a SQL issues. Any help would be greatly appreciated.
Since this is unfortunately way too long for a comment:
Not meaning to be mean, but maybe you shouldn't create a new account to answer your deleted question again (https://stackoverflow.com/questions/59570469) -> Google Cache - also, the Database Classes you're using give away your "real" account (How to retrieve the "total" variable representing a sum in a resultset) - so I'm voting to close this question yet again.
However, to be at least some hints:
ConnectionClass Databaseloader = new ConnectionClass();
Databaseloader.getConnection();
Databaseloader isn't any default JDBC class, but rather some (poorly) written static class, which looks like a weird wrapper to me. You can do it, but by any means you wouldn't do it statically. And by throwing the methods into Google, you find: almost nothing.
For mySQL you'd acquire a database connection like that:
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "sa", "sa")
and rather work with the connection object.
I'd recommend you to do the following:
Read how to connect your database in Java
Read how to create and execute a prepared statement
Read how to extract a result from a result set
Inform yourself about parameter binding (avoid SQL injections)
Profit!
All these topics are well covered on stackoverflow.

Java SE8 JDBC trouble [duplicate]

I'm trying to create a simple method that receives a ResultSet as a parameter and returns an int that contains the row count of the ResultSet. Is this a valid way of doing this or not so much?
int size = 0;
try {
while(rs.next()){
size++;
}
}
catch(Exception ex) {
System.out.println("------------------Tablerize.getRowCount-----------------");
System.out.println("Cannot get resultSet row count: " + ex);
System.out.println("--------------------------------------------------------");
}
I tried this:
int size = 0;
try {
resultSet.last();
size = resultSet.getRow();
resultSet.beforeFirst();
}
catch(Exception ex) {
return 0;
}
return size;
But I got an error saying
com.microsoft.sqlserver.jdbc.SQLServerException:
The requested operation is not supported on forward only result sets.
If you have access to the prepared statement that results in this resultset, you can use
connection.prepareStatement(sql,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
This prepares your statement in a way that you can rewind the cursor. This is also documented in the ResultSet Javadoc
In general, however, forwarding and rewinding cursors may be quite inefficient for large result sets. Another option in SQL Server would be to calculate the total number of rows directly in your SQL statement:
SELECT my_table.*, count(*) over () total_rows
FROM my_table
WHERE ...
Statement s = cd.createStatement();
ResultSet r = s.executeQuery("SELECT COUNT(*) AS recordCount FROM FieldMaster");
r.next();
int count = r.getInt("recordCount");
r.close();
System.out.println("MyTable has " + count + " row(s).");
Sometimes JDBC does not support following method gives Error like `TYPE_FORWARD_ONLY' use this solution
Sqlite does not support in JDBC.
resultSet.last();
size = resultSet.getRow();
resultSet.beforeFirst();
So at that time use this solution.
your sql Statement creating code may be like
statement = connection.createStatement();
To solve "com.microsoft.sqlserver.jdbc.SQLServerException: The requested operation is not supported on forward only result sets" exception, change above code with
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
After above change you can use
int size = 0;
try {
resultSet.last();
size = resultSet.getRow();
resultSet.beforeFirst();
}
catch(Exception ex) {
return 0;
}
return size;
to get row count
I just made a getter method.
public int getNumberRows(){
try{
statement = connection.creatStatement();
resultset = statement.executeQuery("your query here");
if(resultset.last()){
return resultset.getRow();
} else {
return 0; //just cus I like to always do some kinda else statement.
}
} catch (Exception e){
System.out.println("Error getting row count");
e.printStackTrace();
}
return 0;
}
Do a SELECT COUNT(*) FROM ... query instead.
Most drivers support forward only resultset - so method like last, beforeFirst etc are not supported.
The first approach is suitable if you are also getting the data in the same loop - otherwise the resultSet has already been iterated and can not be used again.
In most cases the requirement is to get the number of rows a query would return without fetching the rows. Iterating through the result set to find the row count is almost same as processing the data. It is better to do another count(*) query instead.
If you have table and are storing the ID as primary and auto increment then this will work
Example code to get the total row count http://www.java2s.com/Tutorial/Java/0340__Database/GettheNumberofRowsinaDatabaseTable.htm
Below is code
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
public class Main {
public static void main(String[] args) throws Exception {
Connection conn = getConnection();
Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
st.executeUpdate("create table survey (id int,name varchar(30));");
st.executeUpdate("insert into survey (id,name ) values (1,'nameValue')");
st.executeUpdate("insert into survey (id,name ) values (2,null)");
st.executeUpdate("insert into survey (id,name ) values (3,'Tom')");
st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM survey");
rs = st.executeQuery("SELECT COUNT(*) FROM survey");
// get the number of rows from the result set
rs.next();
int rowCount = rs.getInt(1);
System.out.println(rowCount);
rs.close();
st.close();
conn.close();
}
private static Connection getConnection() throws Exception {
Class.forName("org.hsqldb.jdbcDriver");
String url = "jdbc:hsqldb:mem:data/tutorial";
return DriverManager.getConnection(url, "sa", "");
}
}
Your function will return the size of a ResultSet, but its cursor will be set after last record, so without rewinding it by calling beforeFirst(), first() or previous() you won't be able to read its rows, and rewinding methods won't work with forward only ResultSet (you'll get the same exception you're getting in your second code fragment).
Others have already answered how to solve your problem, so I won't repeat what has already been said, but I will says this: you should probably figure out a way to solve your problems without knowing the result set count prior to reading through the results.
There are very few circumstances where the row count is actually needed prior to reading the result set, especially in a language like Java. The only case I think of where a row count would be necessary is when the row count is the only data you need(in which case a count query would be superior). Otherwise, you are better off using a wrapper object to represent your table data, and storing these objects in a dynamic container such as an ArrayList. Then, once the result set has been iterated over, you can get the array list count. For every solution that requires knowing the row count before reading the result set, you can probably think of a solution that does so without knowing the row count before reading without much effort. By thinking of solutions that bypass the need to know the row count before processing, you save the ResultSet the trouble of scrolling to the end of the result set, then back to the beginning (which can be a VERY expensive operation for large result sets).
Now of course I'm not saying there are never situations where you may need the row count before reading a result set. I'm just saying that in most circumstances, when people think they need the result set count prior to reading it, they probably don't, and it's worth taking 5 minutes to think about whether there is another way.
Just wanted to offer my 2 cents on the topic.
Following two options worked for me:
1) A function that returns the number of rows in your ResultSet.
private int resultSetCount(ResultSet resultSet) throws SQLException{
try{
int i = 0;
while (resultSet.next()) {
i++;
}
return i;
} catch (Exception e){
System.out.println("Error getting row count");
e.printStackTrace();
}
return 0;
}
2) Create a second SQL statement with the COUNT option.
The ResultSet has it's methods that move the Cursor back and forth depending on the option provided. By default, it's forward moving(TYPE_FORWARD_ONLY ResultSet type).
Unless CONSTANTS indicating Scrollability and Update of ResultSet properly, you might end up getting an error.
E.g. beforeLast()
This method has no effect if the result set contains no rows.
Throws Error if it's not TYPE_FORWARD_ONLY.
The best way to check if empty rows got fetched --- Just to insert new record after checking non-existence
if( rs.next() ) {
Do nothing
} else {
No records fetched!
}
See here
Here's some code that avoids getting the count to instantiate an array, but uses an ArrayList instead and just before returning converts the ArrayList to the needed array type.
Note that Supervisor class here implements ISupervisor interface, but in Java you can't cast from object[] (that ArrayList's plain toArray() method returns) to ISupervisor[] (as I think you are able to do in C#), so you have to iterate through all list items and populate the result array.
/**
* Get Supervisors for given program id
* #param connection
* #param programId
* #return ISupervisor[]
* #throws SQLException
*/
public static ISupervisor[] getSupervisors(Connection connection, String programId)
throws SQLException
{
ArrayList supervisors = new ArrayList();
PreparedStatement statement = connection.prepareStatement(SQL.GET_SUPERVISORS);
try {
statement.setString(SQL.GET_SUPERVISORS_PARAM_PROGRAMID, programId);
ResultSet resultSet = statement.executeQuery();
if (resultSet != null) {
while (resultSet.next()) {
Supervisor s = new Supervisor();
s.setId(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ID));
s.setFirstName(resultSet.getString(SQL.GET_SUPERVISORS_RESULT_FIRSTNAME));
s.setLastName(resultSet.getString(SQL.GET_SUPERVISORS_RESULT_LASTNAME));
s.setAssignmentCount(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ASSIGNMENT_COUNT));
s.setAssignment2Count(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ASSIGNMENT2_COUNT));
supervisors.add(s);
}
resultSet.close();
}
} finally {
statement.close();
}
int count = supervisors.size();
ISupervisor[] result = new ISupervisor[count];
for (int i=0; i<count; i++)
result[i] = (ISupervisor)supervisors.get(i);
return result;
}
From http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/ResultSetMetaData.html
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
A ResultSet contains metadata which gives the number of rows.

JAVA Writing to Access database and retrieving and index

I'm writing data from Java to an Access database on Windows 32 bit. When I write a record, I need to retrieve the row ID / primary key so that I can a) update the record easily if I want to and b) cross reference other data to that record.
When did something similar in C, I could make a updatable cursor which allowed me to write a new record and simultaneously retrieve the row ID. With Java, it looks as though I should be able to do this, but it throws an exception with the following code.
con = openAccessDatabase();
String selectString = "SELECT ID, RunCount FROM SpeedTable";
try {
PreparedStatement selectStatement = con.prepareStatement(selectString,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet idResult = selectStatement.executeQuery();
int id;
for (int i = 0; i < nWrites; i++) {
idResult.moveToInsertRow();
idResult.updateObject(1, null); // this line makes no difference whatsoever !
idResult.updateInt(2, i);
idResult.insertRow(); // throws java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver]Error in row
id = idResult.getInt(1);
}
selectStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
The only thing I've been able to do is to write a new record and then run a different query to get the Row id back ...
String insertString = "INSERT INTO SpeedTable (RunCount) VALUES (?)";
String idString = "SELECT ID FROM SpeedTable ORDER BY ID DESC";
//
try {
ResultSet idResult = null;
PreparedStatement preparedStatement, idStatement;
preparedStatement = con.prepareStatement(insertString,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
idStatement = con.prepareStatement(idString,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
for (int i = 0; i < nWrites; i++) {
// write the data into the database
preparedStatement.setInt(1, i);
preparedStatement.execute();
// re-run the query to get the index back from the database.
idResult = idStatement.executeQuery();
idResult.next();
int lastIndex = idResult.getInt(1);
idResult.close();
}
This works but becomes impossibly slow when the table has more than a few 10's of 1000's of records in it. There is also a risk of returning the wrong ID if two parts of the program start writing at the same time (unlikely but not impossible).
I know that at least one suggestion will be to either not use Java or not use Access, but they are not options. It's also part of a free open source software package, so I'm reluctant to pay for anything. Writing my own C JNI interface which provides the basic functionality that I need for my application is even less appealing.
Not sure if this works for MS Access but you can try:
st.executeUpdate("INSERT INTO SpeedTable (RunCount) VALUES (1000)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = st.getGeneratedKeys();
rs.next();
long id = rs.getLong(1);

How to get row count using ResultSet in Java?

I'm trying to create a simple method that receives a ResultSet as a parameter and returns an int that contains the row count of the ResultSet. Is this a valid way of doing this or not so much?
int size = 0;
try {
while(rs.next()){
size++;
}
}
catch(Exception ex) {
System.out.println("------------------Tablerize.getRowCount-----------------");
System.out.println("Cannot get resultSet row count: " + ex);
System.out.println("--------------------------------------------------------");
}
I tried this:
int size = 0;
try {
resultSet.last();
size = resultSet.getRow();
resultSet.beforeFirst();
}
catch(Exception ex) {
return 0;
}
return size;
But I got an error saying
com.microsoft.sqlserver.jdbc.SQLServerException:
The requested operation is not supported on forward only result sets.
If you have access to the prepared statement that results in this resultset, you can use
connection.prepareStatement(sql,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
This prepares your statement in a way that you can rewind the cursor. This is also documented in the ResultSet Javadoc
In general, however, forwarding and rewinding cursors may be quite inefficient for large result sets. Another option in SQL Server would be to calculate the total number of rows directly in your SQL statement:
SELECT my_table.*, count(*) over () total_rows
FROM my_table
WHERE ...
Statement s = cd.createStatement();
ResultSet r = s.executeQuery("SELECT COUNT(*) AS recordCount FROM FieldMaster");
r.next();
int count = r.getInt("recordCount");
r.close();
System.out.println("MyTable has " + count + " row(s).");
Sometimes JDBC does not support following method gives Error like `TYPE_FORWARD_ONLY' use this solution
Sqlite does not support in JDBC.
resultSet.last();
size = resultSet.getRow();
resultSet.beforeFirst();
So at that time use this solution.
your sql Statement creating code may be like
statement = connection.createStatement();
To solve "com.microsoft.sqlserver.jdbc.SQLServerException: The requested operation is not supported on forward only result sets" exception, change above code with
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
After above change you can use
int size = 0;
try {
resultSet.last();
size = resultSet.getRow();
resultSet.beforeFirst();
}
catch(Exception ex) {
return 0;
}
return size;
to get row count
I just made a getter method.
public int getNumberRows(){
try{
statement = connection.creatStatement();
resultset = statement.executeQuery("your query here");
if(resultset.last()){
return resultset.getRow();
} else {
return 0; //just cus I like to always do some kinda else statement.
}
} catch (Exception e){
System.out.println("Error getting row count");
e.printStackTrace();
}
return 0;
}
Do a SELECT COUNT(*) FROM ... query instead.
Most drivers support forward only resultset - so method like last, beforeFirst etc are not supported.
The first approach is suitable if you are also getting the data in the same loop - otherwise the resultSet has already been iterated and can not be used again.
In most cases the requirement is to get the number of rows a query would return without fetching the rows. Iterating through the result set to find the row count is almost same as processing the data. It is better to do another count(*) query instead.
If you have table and are storing the ID as primary and auto increment then this will work
Example code to get the total row count http://www.java2s.com/Tutorial/Java/0340__Database/GettheNumberofRowsinaDatabaseTable.htm
Below is code
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
public class Main {
public static void main(String[] args) throws Exception {
Connection conn = getConnection();
Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
st.executeUpdate("create table survey (id int,name varchar(30));");
st.executeUpdate("insert into survey (id,name ) values (1,'nameValue')");
st.executeUpdate("insert into survey (id,name ) values (2,null)");
st.executeUpdate("insert into survey (id,name ) values (3,'Tom')");
st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM survey");
rs = st.executeQuery("SELECT COUNT(*) FROM survey");
// get the number of rows from the result set
rs.next();
int rowCount = rs.getInt(1);
System.out.println(rowCount);
rs.close();
st.close();
conn.close();
}
private static Connection getConnection() throws Exception {
Class.forName("org.hsqldb.jdbcDriver");
String url = "jdbc:hsqldb:mem:data/tutorial";
return DriverManager.getConnection(url, "sa", "");
}
}
Your function will return the size of a ResultSet, but its cursor will be set after last record, so without rewinding it by calling beforeFirst(), first() or previous() you won't be able to read its rows, and rewinding methods won't work with forward only ResultSet (you'll get the same exception you're getting in your second code fragment).
Others have already answered how to solve your problem, so I won't repeat what has already been said, but I will says this: you should probably figure out a way to solve your problems without knowing the result set count prior to reading through the results.
There are very few circumstances where the row count is actually needed prior to reading the result set, especially in a language like Java. The only case I think of where a row count would be necessary is when the row count is the only data you need(in which case a count query would be superior). Otherwise, you are better off using a wrapper object to represent your table data, and storing these objects in a dynamic container such as an ArrayList. Then, once the result set has been iterated over, you can get the array list count. For every solution that requires knowing the row count before reading the result set, you can probably think of a solution that does so without knowing the row count before reading without much effort. By thinking of solutions that bypass the need to know the row count before processing, you save the ResultSet the trouble of scrolling to the end of the result set, then back to the beginning (which can be a VERY expensive operation for large result sets).
Now of course I'm not saying there are never situations where you may need the row count before reading a result set. I'm just saying that in most circumstances, when people think they need the result set count prior to reading it, they probably don't, and it's worth taking 5 minutes to think about whether there is another way.
Just wanted to offer my 2 cents on the topic.
Following two options worked for me:
1) A function that returns the number of rows in your ResultSet.
private int resultSetCount(ResultSet resultSet) throws SQLException{
try{
int i = 0;
while (resultSet.next()) {
i++;
}
return i;
} catch (Exception e){
System.out.println("Error getting row count");
e.printStackTrace();
}
return 0;
}
2) Create a second SQL statement with the COUNT option.
The ResultSet has it's methods that move the Cursor back and forth depending on the option provided. By default, it's forward moving(TYPE_FORWARD_ONLY ResultSet type).
Unless CONSTANTS indicating Scrollability and Update of ResultSet properly, you might end up getting an error.
E.g. beforeLast()
This method has no effect if the result set contains no rows.
Throws Error if it's not TYPE_FORWARD_ONLY.
The best way to check if empty rows got fetched --- Just to insert new record after checking non-existence
if( rs.next() ) {
Do nothing
} else {
No records fetched!
}
See here
Here's some code that avoids getting the count to instantiate an array, but uses an ArrayList instead and just before returning converts the ArrayList to the needed array type.
Note that Supervisor class here implements ISupervisor interface, but in Java you can't cast from object[] (that ArrayList's plain toArray() method returns) to ISupervisor[] (as I think you are able to do in C#), so you have to iterate through all list items and populate the result array.
/**
* Get Supervisors for given program id
* #param connection
* #param programId
* #return ISupervisor[]
* #throws SQLException
*/
public static ISupervisor[] getSupervisors(Connection connection, String programId)
throws SQLException
{
ArrayList supervisors = new ArrayList();
PreparedStatement statement = connection.prepareStatement(SQL.GET_SUPERVISORS);
try {
statement.setString(SQL.GET_SUPERVISORS_PARAM_PROGRAMID, programId);
ResultSet resultSet = statement.executeQuery();
if (resultSet != null) {
while (resultSet.next()) {
Supervisor s = new Supervisor();
s.setId(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ID));
s.setFirstName(resultSet.getString(SQL.GET_SUPERVISORS_RESULT_FIRSTNAME));
s.setLastName(resultSet.getString(SQL.GET_SUPERVISORS_RESULT_LASTNAME));
s.setAssignmentCount(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ASSIGNMENT_COUNT));
s.setAssignment2Count(resultSet.getInt(SQL.GET_SUPERVISORS_RESULT_ASSIGNMENT2_COUNT));
supervisors.add(s);
}
resultSet.close();
}
} finally {
statement.close();
}
int count = supervisors.size();
ISupervisor[] result = new ISupervisor[count];
for (int i=0; i<count; i++)
result[i] = (ISupervisor)supervisors.get(i);
return result;
}
From http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/ResultSetMetaData.html
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
A ResultSet contains metadata which gives the number of rows.

When are two columns that look the same not the same in oracle?

I am work on a project in oracle 9i. I was having a problem with toplink 10.1.3 loading a particular row in a table. It turns out the jdbc driver that toplink is relying on is acting very funny. Perhaps someone here can help...
I have a table named: crazytable. It has a column: "ver_num number(19) not null default 0". This column was added to the table as part of the original insert some years ago. When I select any record (see below for jdbc connection code) from crazytable and attempt to do an rs.getLong(colIndex), everything works fine. However, if I do a rs.getObject(colIndex), I get a stacktrace:
java.lang.ArrayIndexOutOfBoundsException: 1
at oracle.sql.NUMBER.toBigDecimal(NUMBER.java:651)
at oracle.jdbc.dbaccess.DBConversion.NumberBytesToBigDecimal(DBConversion.java:2805)
at oracle.jdbc.driver.OracleStatement.getBigDecimalValue(OracleStatement.java:4539)
at oracle.jdbc.driver.OracleStatement.getObjectValue(OracleStatement.java:5666)
at oracle.jdbc.driver.OracleStatement.getObjectValue(OracleStatement.java:5622)
at oracle.jdbc.driver.OracleResultSetImpl.getObject(OracleResultSetImpl.java:739)
at oracle.jdbc.driver.OracleResultSet.getObject(OracleResultSet.java:1470)
stacktrace truncated to protect my poor code...
I can take another table, lets call it: sanetable, and run this same query against a column with the same name and type "ver_num number(19) not null default 0". And rs.getLong(colIndex) and rs.getObject(colIndex) work just fine.
Neither column is involved in a constraint, or index. I have tried oracle driver 9.2.0.8, 9.2.0.5, 9.2.0.1, even 10.* (which won't work).
Does anyone know anything about what I can do here?
This is my basic connection code. The only difference between the successful calls is the particular table in question:
Class.forName(oracle.jdbc.OracleDriver.class.getName());
String url = "jdbc:oracle:thin:#IPADDRESS:PORT:INSTANCE";
Connection conn = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(url, "user","pass");
PreparedStatement prepareStatement = conn.prepareStatement(
"select distinct ver_num " +
"FROM [crazytable|sanetable] "
);
rs = prepareStatement.executeQuery();
assertNotNull(rs);
while (rs.next()) {
ResultSetMetaData md = rs.getMetaData();
for (int i = 1; i <= md.getColumnCount(); i++) {
String key = md.getColumnLabel(i);
Object value = rs.getLong(key);
System.out.println(key+" : "+value
+" was null: "+rs.wasNull()
+" type: "+ rs.getType()
+" class: "+ md.getColumnClassName(i));
}
}
} finally {
if (rs != null) {
rs.close();
}
if (conn != null) {
conn.close();
}
}
edit: The driver can be found on this page: http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc9201.html
Okay I think I figured this out. I was looking through some other questions and noticed there are other oracle type 4 drivers. One of which is DataDirect (http://datadirect.com). I used a trial version of their driver and it was able to return the rs.getObject(intIndex).
The value was: -1.6777120E-27.
So rs.getLong() was rounding down to zero, but the BigDecimal was seeing a decimal part and throwing an exception.
Perhaps this is due to oracle's driver being compiled with jdbc1.4 vs, something newer for datadirect.

Categories