I'm trying to access my database, inject some SQL Code and return the value out of it.
First of all, I'm a new to this stuff but I've came up with the following code:
public static ResultSet checkCmdAmount() throws Exception {
try {
// This will load the MySQL driver, each DB has its own driver
Class.forName("com.mysql.jdbc.Driver");
// Setup the connection with the DB
connect = DriverManager.getConnection(""+MyBot.mysqlDbPath+"",""+MyBot.mysqlDbUsername+"",""+MyBot.mysqlDbPassword+"");
PreparedStatement zpst=null;
ResultSet zrs=null;
zpst=connect.prepareStatement("SELECT COUNT(1) FROM eigenebenutzerbefehle");
zrs=zpst.executeQuery();
return zrs;
}catch (Exception e) {
throw e;
} finally {
close();
}
}
In my return, I get the following:
ResultSet: com.mysql.jdbc.JDBC4ResultSet#196da649
But I want actually the Amount of rows in my table.
When I execute the sql code through phpmyadmin I get 3 which is correct.
What is wrong here?
You need to read and get the desired values from the ResultSet. Do it as below:
public static int checkCmdAmount() throws Exception {
// ...
int count = 0;
while (zrs.next()) {
// Get the values from the current row...
count = zrs.getInt(1);
}
return count;
}
A ResultSet object contains all rows returned by executing an SQL query using a PreparedStatment or Statement from a database.
So when you executed
ResultSet zrs=null;
zpst=connect.prepareStatement("SELECT COUNT(1) FROM eigenebenutzerbefehle");
zrs=zpst.executeQuery();
return zrs;
as you said your SQL query will return number of rows, and that information is stored in ResultSet object zrs, but a ResultSet object's job is to store all the rows containing values from all columns specified or all rows in case of using *.
And when you are returning zrs you are returning a ResultSet object, and when you try and print an object what you get is the default value for an object's toString() conversion, which is in most cases objects types fully qualified name + a few extra characters.
And your updated code executes
if(zrs.next()){
return zrs.getInt(1);
}
else{
return -1;
}
here zrs.next() call moves the zrs to valid next record(or row) from where values can be retrieved, it also returns true or false depending upon the presence of record. In your example if you add one more call to zrs.next() then it would be returning false.
zrs.getInt(1) will return the value in the row the zrs pointing to and the value of the first column, it has in that row, which is in your case only column.
Related
I want to display a record from an Oracle database in Java using select keyword, but it's not working. When I run the program it displays the SQL command but not the result I want.
My code is like this:
static void modify()
{
System.out.println("Enter employee ID");
empid=sc.nextInt();
try{
con=Connection1.getConnection();
stmt=con.createStatement();
String d="select * from emp where empid='"+empid+"'";
rs=stmt.executeQuery(d);
System.out.println(""+d);
}
catch(SQLException e)
{
e.printStackTrace();
}
}
When I run the application this result is shown instead of record from database:
select * from emp where empid='14'
The problem is you are just printing the name of your results not the results itself.
I have changed your code as below,
static void modify()
{
System.out.println("Enter employee ID");
empid=sc.nextInt();
try{
con=Connection1.getConnection();
stmt=con.createStatement();
String d="select * from emp where empid='"+empid+"'";
rs=stmt.executeQuery(d);
while(rs.next()){
//Getting column value from record by giving column no
System.out.println(rs.getString(1)); //line 1
//Getting column value from record by giving column name,
System.out.println(rs.getString("empid"));// line 2
}
}
catch(SQLException e)
{
e.printStackTrace();
}
}
Please note that above code (line 1) will print the first column of your each records( returned from db), here the order of the returned columns is not guaranteed.
If you want to get Specific column then you can specify the column name as argument in the getString method of resultSet (line 2).
You have to use appropriate methods to get values such that , if column 2 has the data type in DB as INTEGER then you have to use rs.getInt(2).
In your code,
System.out.println(""+rs);
In Java when you call println(Object) method in System.out,which will call String.valueOf(Object) method which is again will call toString() method, which would return the String representation of your object, here nothing but the query you passed, not the records.
You are printing the toString() representation of the Statement. Instead, you should execute the statement (which you did), and get the relevant string from the ResultSet.
Frankly, RestulSet doesn't give the most comfortable way to iterate its columns, but it's doable:
int colCount = rs.getMetaData().getColumnCount()
List<Object> columnValues = new ArrayList<>(colCount);
// Move to the first row
// If your query returns more than one row,
// you'd probably want to iterate over all of them
rs.next();
// Iterate the columns:
for (int i = 1; i <= colCount; ++i) {
list.add(rs.getObject(i));
}
System.out.println ("Record: " + list);
I have two methods in my class, First I am calling method dbExecuteStatement(), which execute the sql query. After execution of sql query, I get a ResultSet object. I am saving this ResultSet object in a static hashMap, so that on my next method call fetchResults(), I can use the existing result set to retrieve the results. Reason for saving the ResultSet object in a map is ,in fetchResults() method request parameter, I will get the max fetch row size, and on basis of that value I will be iterating the result set. Both of this methods are supposed to be called individual from the client side.
Now the problem, I am facing is that, When I am iterating the ResultSet object in fetchResults() method, I am getting the row count zero. If I fetch the same ResultSet from a hashMap in dbExecuteStatement(), I get the actual row count i.e 5 in my case. I checked the ResultSet object that I have put in the hash map in fetchResults() method and dbExecuteStatement(), it is the same object. But If get the ResultSetMetaData object in fetchResults() method and dbExecuteStatement(), they are coming different. Can someone help me in understanding the cause, Why I am getting the result count zero.
Below is the code:
public class HiveDao1 {
private static Map<Object,Map<Object,Object>> databaseConnectionDetails
= new HashMap<Object,Map<Object,Object>>();
//This method will execute the sql query and will save the ResultSet obj in a hashmap for later use
public void dbExecuteStatement(DbExecuteStatementReq dbExecuteStatementReq){
//I already have a connection object saved in map
String uniqueIdForConnectionObject = dbExecuteStatementReq.getDbUniqueConnectionHandlerId();
Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);
Connection connection = (Connection) dbObject.get(DatabaseConstants.CONNECTION);
try {
Statement stmt = connection.createStatement() ;
// Execute the query
ResultSet resultSet = stmt.executeQuery(dbExecuteStatementReq.getStatement().trim()) ;
//save the result set for further use, Result set will be used in fetchResult() call
dbObject.put(DatabaseConstants.RESULTSET, resultSet);
/*
* Now below is the debugging code,which I put to compare the result set
* iteration dbExecuteStatement() and fetchResults method
*/
ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);
ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);
System.out.println("==ResultSet fethced in dbExecuteStatement=="+rs);
System.out.println("==ResultSet metadata fetched in dbExecuteStatement ==="+rs.getMetaData());
int count = 0;
while (rs.next()) {
++count;
}
if (count == 0) {
System.out.println("No records found");
}
System.out.println("No of rows found from result set in dbExecuteStatement is "+count);
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* This method fetch the result set object from hashMap
* and iterate it on the basis of fetch size received in req parameter
*/
public void fetchResults(FetchResultsReq fetchResultsReq){
String uniqueIdForConnectionObject = fetchResultsReq.getDbUniqueConnectionHandlerId();
Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);
try {
//Fetch the ResultSet object that was saved by dbExecuteStatement()
ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);
ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);
System.out.println("ResultSet fethced in fetchResults at server side dao layer======"+rs);
System.out.println("ResultSet metadata fetched in fetchResults at server side dao layer======"+md);
int count = 0;
while (rs.next()) {
++count;
}
if (count == 0) {
System.out.println("No records found");
}
//Here the row count is not same as row count in dbExecuteStatement()
System.out.println("No of rows found from result set in fetchResults is "+count);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Expanding on my comment (And #Glenn's):
Using a ResultSet more than once
When you write debug code that iterates a ResultSet, the cursor moves to the end of the results. Of course, if you then call the same object and use next(), it will still be at the end, so you won't get any more records.
If you really need to read from the same ResultSet more than once, you need to execute the query such that it returns a scrollable ResultSet. You do this when you create the statement:
Statement stmt = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY );
The default statement created by connection.createStatement() without parameters returns a result set of type ResultSet.TYPE_FORWARD_ONLY, and that ResultSet object can only be read once.
If your result set type is scroll insensitive or scroll sensitive, you can use a statement like rs.first() to reset the cursor and then you can fetch the records again.
Keeping the statement in scope
#Glenn's comment is extremely important. The way your program works right now, it may work fine throughout the testing phase, and then suddenly in production, you'll sometimes have zero records in your ResultSet, and the error will be reproducible only occasionally - a debug nightmare.
If the Statement object that produces the ResultSet is closed, the ResultSet itself is also closed. Since you are not closing your Statement object yourself, this will be done when the Statement object is finalized.
The stmt variable is local, and it's the only reference to that Statement that we know of. Therefore, it will be claimed by the garbage collector. However, objects that have a finalizer are relegated to a finalization queue, and there is no way of knowing when the finalizer will be called, and no way to control it. Once it happens, the ResultSet becomes closed out of your control.
So be sure to keep a reference to the statement object alongside your ResultSet. And make sure you close it properly yourself once you are done with the ResultSet and will not be using it anymore. And after you close it remember to remove the reference you have kept - both for the statement and the result set - to avoid memory leaks. Closing is important, and relying on finalizers is a bad strategy. If you don't close it yourself, you might run out of cursors at some point in your database (depending on the DBMS and its configuration).
Can anybody tell me why the below method (executeUpdate) is always returning 1 even if I have specified to return the generated key in it? I want to get the generated key in generatedKey variable. It works fine for PreparedStatement using getGeneratedKeys, but I want to do it with Statement.
public int testQuery(Connection con) {
int generatedKey = 0;
try {
Statement statement = con.createStatement();
generatedKey = statement.executeUpdate("INSERT INTO profile (fullname) VALUES ('Visruth CV')", Statement.RETURN_GENERATED_KEYS);
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
con.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
System.out.println("generated key : "+generatedKey);
return generatedKey;
}
As per the documentation of executeUpdate(String sql, int autoGeneratedKeys), it says :
Executes the given SQL statement and signals the driver with the given flag about whether the auto-generated keys produced by this Statement object should be made available for retrieval. The driver will ignore the flag if the SQL statement is not an INSERT statement, or an SQL statement able to return auto-generated keys (the list of such statements is vendor-specific).
Parameters:
sql an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or DELETE; or an SQL statement that returns nothing, such as a DDL statement.
autoGeneratedKeys a flag indicating whether auto-generated keys should be made available for retrieval; one of the following constants: Statement.RETURN_GENERATED_KEYS Statement.NO_GENERATED_KEYS
Returns:
either (1) the row count for SQL Data Manipulation Language (DML) statements or (2) 0 for SQL statements that return nothing
Throws:
SQLException - if a database access error occurs, this method is called on a closed Statement, the given SQL statement returns a ResultSet object, or the given constant is not one of those allowed
SQLFeatureNotSupportedException - if the JDBC driver does not support this method with a constant of Statement.RETURN_GENERATED_KEYS
Since:
1.4
It says in the javadoc you pasted:
returns: either (1) the row count for SQL Data Manipulation Language or (2) 0 for SQL statements that return nothing
It's returning 1 because you're always inserting only 1 value. It does not return the generated key.
To get the generated keys, you need to run this line:
rs = stmt.getGeneratedKeys()
You can read a full tutorial about this concept here.
If you read the Returnspart of the documentation it doesn't say that it will return the generated keys. It returns either a row count or 0.
Use getGeneratedKeys() after you have executed the statement to get generated keys.
I am retrieving a simple ResultSet from my SQL Server database using the Microsoft JDBC Driver (mssqlserver.jar). I think it is the MSSQL2000 Driver which is downloaded from [Microsoft JDBC][1]
I am wanting to call the getter methods more than once to access the values but when you do the following exception is thrown:
java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]ResultSet can not re-read row data for column 1.
Question is, I am retrieving data into a ResultSet. From the ResultSet, I am accessing the data in my code before passing the ResultSet on to elsewhere in code to be reused.
Code is similar to as follows:
// build query string
String selectQuery = "SELECT * FROM SomeWhere";
// get the data
Statement statement = sourceConnection.createStatement();
ResultSet rs = statement.executeQuery(selectQuery);
while( rs.next() ) {
// do my own internal processing
doSomethingWithRs(rs);
// now do something with the record set outside - in subclass
afterRowCopied(rs);
}
// ...
private void doSomethingWithRs(ResultSet rs) {
// access data
for( int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
Object o = rs.getObject(i);
// do something with o...
}
}
Edit
I am using Java 1.6 for this.
end Edit
Any thoughts?
All I can think of doing is repackaging the data with the ResultSetMetaData into a custom class.
Not really found too much posts on this issue. Microsoft website not any help at all.
This seems to be by design, according to "ResultSet Can Not Re-Read Row Data"' Error When Reading Data from a JDBC ResultSet Object:
This error occurs with ResultSet objects that contain a BLOB column (for example, text, ntext, or image data types). The driver cannot return a BLOB column out of order because it does not cache all the content of BLOB data types because of size limitations.
For any row in the ResultSet, you can read any column from left to right, and each column should be read only one time. If you try to read columns out of order, or if you re-read a column from the ResultSet, you may receive the error message that the "Symptoms" section describes.
This behavior is by design.
You either need to use a different JDBC driver, or refactor your code to only read those BLOB columns once for any given row. This a good idea anyway, since re-reading BLOBs can be a performance killer.
I would suggest reading the data once and copying to an Object array and passing it to methods instead of passing the resultset. That can be more clean code also.
The long winded nightmare approach (which does work) but I have lazily just implemented most of the getters.
Edit
As I mentioned, I am using JDK 1.6. However, when compiled against the JDK 1.7 a compilation error is encountered:
error: ReadOnlyResultSet is not abstract and does not override abstract method <T>getObject(String,Class<T>) in ResultSet
end Edit
To do this create a class that implements the ResultSet (Let Netbeans add the default method implementation stubs). Then in the constructor, store a reference to the initial ResultSet. In next(), cache the values in an array. Proabably have to do the same for previous() and other set cursor methods. So the class will look like:
public class ReadOnlyResultSet
implements ResultSet {
/**
* The original data source.
*/
private ResultSet source;
/**
* Cached values for the current row.
*/
private Object[] values;
/**
* Creates a new instance of <code>ReadOnlyResultSet</code>.
*/
public ReadOnlyResultSet(ResultSet source) {
this.source = source;
}
#Override
public boolean next() throws SQLException {
// NOTE: values[0] will always be null as JDBC is 1 based arrays
boolean next = source.next();
if( next ) {
values = new Object[source.getMetaData().getColumnCount() + 1];
for(int i = 1; i < source.getMetaData().getColumnCount(); i++ ) {
values[i] = source.getObject(i);
}
} else {
// no current row
values = new Object[] { };
}
return next;
}
// implement all of the not getter/setter methods
#Override
public void close() throws SQLException {
source.close();
}
// implement getters I am interested in
#Override
public String getString(int columnIndex) throws SQLException {
return (String) values[columnIndex];
}
#Override
public String getString(String columnLabel) throws SQLException {
return (String) values[findColumn(columnLabel)];
}
// just too much implementation but hopefully you get the drift
}
Read the Following Code:
public class selectTable {
public static ResultSet rSet;
public static int total=0;
public static ResultSet onLoad_Opetations(Connection Conn, int rownum,String sql)
{
int rowNum=rownum;
int totalrec=0;
try
{
Conn=ConnectionODBC.getConnection();
Statement stmt = Conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
String sqlStmt = sql;
rSet = stmt.executeQuery(sqlStmt);
total = rSet.getRow();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
System.out.println("Total Number of Records="+totalrec);
return rSet;
}
}
The folowing code dos't show actual total:
total = rSet.getRow();
my jTable display 4 record in jTable but total = 0; when I evaluate through debug, it shows:
total=(int)0;
rather than total=(int)4
And if I use
rSet=last(); above from the code total = rSet.getRow();
then total shows accurate value = 4 but rSet return nothing. then jTable is empty.
Update me!
BalusC's answer is right! but I have to mention according to the user instance variable such as:
rSet.last();
total = rSet.getRow();
and then which you are missing
rSet.beforeFirst();
the remaining code is same you will get your desire result.
You need to call ResultSet#beforeFirst() to put the cursor back to before the first row before you return the ResultSet object. This way the user will be able to use next() the usual way.
resultSet.last();
rows = resultSet.getRow();
resultSet.beforeFirst();
return resultSet;
However, you have bigger problems with the code given as far. It's leaking DB resources and it is also not a proper OOP approach. Lookup the DAO pattern. Ultimately you'd like to end up as
public List<Operations> list() throws SQLException {
// Declare Connection, Statement, ResultSet, List<Operation>.
try {
// Use Connection, Statement, ResultSet.
while (resultSet.next()) {
// Add new Operation to list.
}
} finally {
// Close ResultSet, Statement, Connection.
}
return list;
}
This way the caller has just to use List#size() to know about the number of records.
The getRow() method retrieves the current row number, not the number of rows. So before starting to iterate over the ResultSet, getRow() returns 0.
To get the actual number of rows returned after executing your query, there is no free method: you are supposed to iterate over it.
Yet, if you really need to retrieve the total number of rows before processing them, you can:
ResultSet.last()
ResultSet.getRow() to get the total number of rows
ResultSet.beforeFirst()
Process the ResultSet normally
As others have answered there is no way to get the count of rows without iterating till the end. You could do that, but you may not want to, note the following points:
For a many RDBMS systems ResultSet is a streaming API, this means
that it does not load (or maybe even fetch) all the rows from the
database server. See this question on SO. By iterating to the
end of the ResultSet you may add significantly to the time taken to
execute in certain cases.
A default ResultSet object is not updatable and has a cursor
that moves forward only. I think this means that unless you
execute
the query with ResultSet.TYPE_SCROLL_INSENSITIVE rSet.beforeFirst() will throw
SQLException. The reason it is this way is because there is cost
with scrollable cursor. According to the documentation, it may throw SQLFeatureNotSupportedException even if you create a scrollable cursor.
Populating and returning a List<Operations> means that you will
also need extra memory. For very large resultsets this will not
work
at all.
So the big question is which RDBMS?. All in all I would suggest not logging the number of records.
One better way would be to use SELECT COUNT statement of SQL.
Just when you need the count of number of rows returned, execute another query returning the exact number of result of that query.
try
{
Conn=ConnectionODBC.getConnection();
Statement stmt = Conn.createStatement();
String sqlStmt = sql;
String sqlrow = SELECT COUNT(*) from (sql) rowquery;
String total = stmt.executeQuery(sqlrow);
int rowcount = total.getInt(1);
}
The getRow() method will always yield 0 after a query:
ResultSet.getRow()
Retrieves the current row number.
Second, you output totalrec but never assign anything to it.
You can't get the number of rows returned in a ResultSet without iterating through it. And why would you return a ResultSet without iterating through it? There'd be no point in executing the query in the first place.
A better solution would be to separate persistence from view. Create a separate Data Access Object that handles all the database queries for you. Let it get the values to be displayed in the JTable, load them into a data structure, and then return it to the UI for display. The UI will have all the information it needs then.
I have solved that problem. The only I do is:
private int num_rows;
And then in your method using the resultset put this code
while (this.rs.next())
{
this.num_rows++;
}
That's all
The best way to get number of rows from resultset is using count function query for database access and then rs.getInt(1) method to get number of rows.
from my code look it:
String query = "SELECT COUNT() FROM table";
ResultSet rs = new DatabaseConnection().selectData(query);
rs.getInt(1);
this will return int value number of rows fetched from database.
Here DatabaseConnection().selectData() is my code for accessing database.
I was also stuck here but then solved...