Returning SQL Count function to Java - java

I'm having problems getting a SQL count query to return the proper value. I know there are already several questions about this topic already posted, but I'm hoping to get a second pair of eyes look over my code to see if they notice anything I've missed. I've found several examples of similar methods that seem to work, and as far as I can see, mine is the same. Here's my method that calls the SQL query:
public int countAddresses(int id) {
ResultSet rs = null;
Statement st = null;
int count = -1;
try{
st = conn.createStatement();
String countAddress = "SELECT COUNT(*) AS AddressCount from address WHERE contact_id =" + id;
rs = st.executeQuery(countAddress);
count = rs.getInt("AddressCount"); //throwing exception
}
catch(SQLException e) {
e.printStackTrace();
}
return count;
}
No matter what tweaks I make, it always returns -1 because the line that reassigns count throws a SQLException. It's worth noting that all my other methods that contact the database are connecting and returning the proper values, and that my java code calls this method after it has successfully called and returned some of these other methods. If anyone can find an error in my code or needs additional info, please let me know. Thanks.
Additional specs:
Spring MVC
XAMPP with a MySQL db

The reason you get an exception is that you are calling getInt without calling next():
rs = st.executeQuery(countAddress);
if (rs.next()) {
count = rs.getInt("AddressCount");
}
The reason it is illegal to call getInt before calling next is that executeQuery() returns you a reader that is not positioned on the first (in this case, the only) result.

Try using
if( rs.next())
count = rs.getInt(1);

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 - How to get max ID in SQL

It Takes Too Long For Me To Create And Send PreparedStatement's or ResultSet.
How Can I Get MaxID From SQL in Java Method?
Writed this but not working...
private static int getLastId()
{
int returned=0;
try
{
PreparedStatement stat;
ResultSet rs;
String sql="select max(id) from home";
stat=conn.prepareStatement(sql);
rs=stat.executeQuery();
while(rs.next())
{
returned = rs.getInt("id")+1;// just want a new id for new person
}
}
catch (Exception e)
{
System.out.println(""+e);
}
return returned;
}
I Tried To Use It Like This...
//reseting every thing and get lastId+1;
System.out.println("added");
field_name.setText("");
field_pass.setText("");
int temp= getLastId();
field_id.setText(""+temp);
But It Returns 0!
I Don't Have any SQL error.
Did I Use It Wrong?
or ?
Thanks For Help.
You have a few problems here, one of which is that in your current code you aren't actually accessing the max(id) which you put in the query. One way around this is to assign an alias:
PreparedStatement stat;
ResultSet rs;
String sql = "SELECT MAX(id) AS max_id FROM home";
stat = conn.prepareStatement(sql);
rs = stat.executeQuery();
if (rs.next()) {
returned = rs.getInt("max_id") + 1;
}
This fixes the syntax problem, but there is still the problem of whether this is the best way to get the next id. I would recommend that you switch to using an auto increment column, which MySQL will manage for you. Then, you don't need to worry about keeping track of the latest ID value. In fact, you don't even need to specify a value when inserting; the database will handle this for you.

Prepared statement not returning results for string numbers

I am trying to retrieve records from oracle database for the SQL query - SELECT data FROM test where id = ?;
Here is my code to retrieve the data -
public static String retrieveData(String id) throws IOException {
String result = "";
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT data FROM test where id = ?";
connection = getDBConnection(); //this method gets the db connection
ps = connection.prepareStatement(sql);
ps.setString(1, id);
rs = ps.executeQuery();
while(rs.next()) {
result = result + rs.getString("data");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
closeDBConnection(); //closes db connection
}
return result;
}
When I invoke the retrieveData in the main method, it returns null. When I debug, the resultSet is empty. I am guessing the reason is I am passing my id as String, but perhaps Oracle doesn't understand something like - SELECT data FROM test where id = "1234567890";
Can someone please guide me how do I fix this? I have tried way too many things, but I can't seem to fetch the data from the db for this id. I also tried converting the id to long using Long.valueOf(String s).longValue(); and setting this as the placeholder in ps.setLong, but it didn't help. Please advise.
Type issue of id column
This is probably due to spacing difference or another subtle difference that gives the impression that they are the same.
The strings ' 123 ' or '00123' (for example) are not equivalent to '123' in VARCHAR2 type, while they are equivalent in NUMERIC type, as Oracle converts all those strings to the numeral 123.
You are better off using a NUMERIC column as your id to avoid such problems. It also makes sense to limit your valid id values to whole numbers, rather than any arbitrary string.
With Oracle you can continue to use setString as it will automatically cast the string to an integer. But I recommend you to use setInt or setLong instead (after the conversion of the id column), as other database solutions like Postgres will not accept a string to match a NUMERIC column.
Exception handling issue
When you catch a Throwable or an Exception (or their subtypes), be sure to think about whether it can be ignored, or it must be thrown for further handling (for example, to stop the program, alert the user or correct the problem).
In your code, the catch block catches the SQLException and prints the stack trace. But it doesn't do anything else.
} catch (SQLException e) {
e.printStackTrace();
} ...
This means that you are ignoring the exception and continuing the program as though nothing happened. The execution will continue on to return result; after completing the finally block.
The caller of your method will never know that an SQLException occurred, and it will wrongly assume that there were no errors and the returned data is correct.
Unless that is what you really want, what you ought to do is as follows:
} catch (SQLException e) {
e.printStackTrace(); //it doesn't matter what you do here. the next line is what's important.
throw e; //throw the exception after printing stack trace, logging, etc.
} ...
In this case your method will throw the SQLException to the caller after completing the finally block. The execution will not continue to return result;.
This way the caller of your method will receive the exception and know that an error has occurred. The caller can then act accordingly; for example, by stopping the program, alerting the user or retrying the method with a different input.
may be the reason is DEBUG. if you have a breakpoint on the line "while(rs.next())" and you watch/inspect it then then rs increments one. Then the code executes rs.next for the second time where there is no record.
maybe...
You shouldn't use datatype 'String' for id field, it can cause serious trouble. Try to covert it to numeric datatype is possible but why don't you use numeric at first. You should change to int or bigint. In additional try to catch exception like this:
try{
}catch(SQLException ex){
System.out.println("Error at:" +ex.getClass().getName() + ex.getMessage());
}
Try it again, if you can't debug it and find out why! Good luck!
Please try this. Remove all the spaces when defining field name with a ? and check
SELECT data FROM test where id=?

The SECOND resultset is giving error

I am trying to access the column names of 2 different databases; one is SQL and the other is Oracle. The program compiles fine, but while execution it gives an error for the rsmo(resultset for oracle): stating ResultSet.next was not called.
About the program:
I take the databasenames, ip, userid and pass from a text file and store them in strings before passing it to connection. The aim is to copy data from one database to another, but for now all i am doing is finding the column names and number of columns before insertion. At any point of time, there will only be 2 tables viz one of SQL and the other of oracle, to copy to and from. Hence i have an array of colNames for storing the names of the respective columns.
Code snippet:
Connection CONN_SQL = DriverManager.getConnection(URL_SQL, USER_SQL, PASS_SQL);
Connection CONN_ORA = DriverManager.getConnection(URL_ORA, USER_ORA, PASS_ORA);
DatabaseMetaData dmds = CONN_SQL.getMetaData();
DatabaseMetaData dmdo = CONN_ORA.getMetaData();
ResultSet rsms = dmds.getColumns(null, null, SQLTABLENAME, null);
ResultSet rsmo = dmdo.getColumns(null, null, ORACLETABLENAME, null);
String rs;
int columns=1, columno=1;
while(rsms.next() || rsmo.next()){
if(rsms!=null){
colNames[0][columns]=rsms.getString(4);
System.out.println("colnames:" +colNames[0][columns]);
columns++;}
if(rsmo!=null){
System.out.println(rsmo.getString(1));
colNames[1][columno] = rsmo.getString(4);
System.out.println("columno: "+colNames[1][columno]);
columno++;
}
}
Things i have tried and their failures:
Tried 2 while loops for the 2 result sets, the rsms(SQL one) runs perfectly, returning the column names. But the rsmo(oracle one) does not run. It skips the while loop, but executes any statement before AND after it.
I have tried to make another resultset which just executes a SELECT top 20 query for both SQL and oracle. AGAIN, it works properly with SQL but ORACLE's ResultSet is skipped.
I have tried some solutions from stackoverflow such as:
Setting resultset to first, which results in a runtime exception stating "Exhausted ResultSet".
if(!rs.next()), which also results in an Exhausted ResultSet exception.
I just want to know what i am doing wrong, or a solution is always appreciated. Thanks.
UPDATE:
Found out that the resultset isnt allowed to be iterated more than once. Tried closing the ResultSet of SQL, after use, and then opening the other. Still no use, the Oracle RS is skipped again.
In this code
while(rsms.next() || rsmo.next()){
if rsms.next() is evaluated to true, then rsmo.next() will not even be called and may be false.
In you while loop, when would rsms or rsmo suddenly become null?
while (true) {
boolean foundms = false;
boolean foundmo = false;
if (rsms.next()) {
// do stuff
foundms = true;
}
if (rsmo.next()) {
// do stuff
foundmo = true;
}
if (!foundms && !foundmo) break;
}
If this is still not working, then borrowing try (from Darshan's answer )
ResultSet rsmo = dmdo.getColumns(null, null, ORACLETABLENAME, null);
ResultSetMetaData md = rsmo.getMetaData();
for (int i=1; i<=md.getColumnCount(); i++)
{
System.out.println(md.getColumnName(i));
}
You have put OR condition .Which satifies everytiem and is true for SQL alone. Try to seperate while loop and execute
while(rsms.next()){
if(rsms!=null){
colNames[0][columns]=rsms.getString(4);
System.out.println("colnames:" +colNames[0][columns]);
columns++;}}
while(rsmo.next()){
if(rsmo!=null){
System.out.println(rsmo.getString(1));
colNames[1][columno] = rsmo.getString(4);
System.out.println("columno: "+colNames[1][columno]);
columno++;
}
}
The operator '||' in your while loop works in the way that if first statement was true then he does not check any following statements. It is so called short-circuiting. Try to use single '|' sign or splitting in two separate while loops.
Try using following code for oracle
ResultSet rsmo = dmdo.getColumns(null, null, ORACLETABLENAME, null);
ResultSetMetaData md = rsmo.getMetaData();
for (int i=1; i<=md.getColumnCount(); i++)
{
System.out.println(md.getColumnLabel(i));
}
Hope it helps.

Categories