Queries returning multiple result sets - java

I have a MSSQL database and am running the following query:
select * from projects; select * from user
The above query returns two result sets at once, and I cannot fire both queries separately. How can I handle both the result set at once in a Java class?

Correct code to process multiple ResultSets returned by a JDBC statement:
PreparedStatement stmt = ...;
boolean isResultSet = stmt.execute();
int count = 0;
while(true) {
if(isResultSet) {
rs = stmt.getResultSet();
while(rs.next()) {
processEachRow(rs);
}
rs.close();
} else {
if(stmt.getUpdateCount() == -1) {
break;
}
log.info("Result {} is just a count: {}", count, stmt.getUpdateCount());
}
count ++;
isResultSet = stmt.getMoreResults();
}
Important bits:
getMoreResults() and execute() return false to indicate that the result of the statement is just a number and not a ResultSet.
You need to check stmt.getUpdateCount() == -1 to know if there are more results.
Make sure you either close the result sets or use stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT)

You can use Statement.execute(), getResultSet();
PreparedStatement stmt = ... prepare your statement result
boolean hasResults = stmt.execute();
while (hasResults) {
ResultSet rs = stmt.getResultSet();
... your code parsing the results ...
hasResults = stmt.getMoreResults();
}

Yes, You can. See this MSDN article
https://msdn.microsoft.com/en-us/library/ms378758(v=sql.110).aspx
public static void executeStatement(Connection con) {
try {
String SQL = "SELECT TOP 10 * FROM Person.Contact; " +
"SELECT TOP 20 * FROM Person.Contact";
Statement stmt = con.createStatement();
boolean results = stmt.execute(SQL);
int rsCount = 0;
//Loop through the available result sets.
do {
if(results) {
ResultSet rs = stmt.getResultSet();
rsCount++;
//Show data from the result set.
System.out.println("RESULT SET #" + rsCount);
while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
rs.close();
}
System.out.println();
results = stmt.getMoreResults();
} while(results);
stmt.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
I've tested that and it works fine.

Before use java, you need look at the RESULT SETS clause.
MSSQL has this feature that can help you with your java code, in a more practical way.
This example will exec two queries:
EXEC('SELECT id_person, name, age FROM dbo.PERSON; SELECT id_url, url FROM dbo.URL;')
WITH RESULT SETS
(
(
id_person BIGINT,
name VARCHAR(255),
age TINYINT
),
(
id_url BIGINT,
url VARCHAR(2000)
)
);
You can use stored procedures with RESULT SETS as well.
More about: https://technet.microsoft.com/en-us/library/ms188332(v=sql.110).aspx

public static void executeProcedure(Connection con) {
try {
CallableStatement stmt = con.prepareCall(...);
..... //Set call parameters, if you have IN,OUT, or IN/OUT parameters
boolean results = stmt.execute();
int rsCount = 0;
//Loop through the available result sets.
while (results) {
ResultSet rs = stmt.getResultSet();
//Retrieve data from the result set.
while (rs.next()) {
....// using rs.getxxx() method to retrieve data
}
rs.close();
//Check for next result set
results = stmt.getMoreResults();
}
stmt.close();
}
catch (Exception e) {
e.printStackTrace();
}
}

The UNION ALL query allows you to combine the result sets of 2 or more "select" queries. It returns all rows (even if the row exists in more than one of the "select" statements).
Each SQL statement within the UNION ALL query must have the same number of fields in the result sets with similar data types.........
select * from projects
UNION ALL
select * from user

The answer: it is NOT possible. The only way: Run them as separate queries.

Related

Why Boolean execute(String SQL) is always true, even my input is not in my database

This is my code
try{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost/records";
Connection con = DriverManager.getConnection(url,"root","");
Statement st = con.createStatement();
String sql = "SELECT * FROM patient_info WHERE name = '"+txt1.getText()+"' ";
in this part, it always prints true, if I'm right this boolean returns the boolean value of string sql.
Boolean ret = st.execute(sql);
System.out.println(ret.toString());
this if statement I don't know if right
if(ret == true){
ResultSet rs = st.executeQuery(sql);
String name = null;
while(rs.next()) {
name = rs.getString("name");
txt2.setText(name);
System.out.println("working");
}
rs.close();
} else {
txt2.setText("no records");
System.out.println("no records");
}
st.close();
con.close();
}catch(SQLException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStackTrace();
}
From the JavaDoc:
boolean execute​(String sql) throws SQLException
Executes the given SQL statement, which may return multiple results. In some (uncommon) situations, a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string.
The execute method executes an SQL statement and indicates the form of the first result. You must then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s).
Note: This method cannot be called on a PreparedStatement or CallableStatement.
Parameters:
sql - any SQL statement
Returns:
true if the first result is a ResultSet object; false if it is an update count or there are no results
That means that Statement.execute() will return true if the result is a ResultSet – and that is the case even when there is no entry for the SELECT statement in the database. The ResultSet will be just empty in that case – but it is still a ResultSet.
This means, too, that you should modify your code (if you want to stick to the first call Boolean ret = st.execute(sql);) like this:
…
if( ret )
{
ResultSet rs = st.getResultSet();
String name = null;
…
}
This way you avoid the second roundtrip to the database for the execution of Statement.executeQuery().
Or you do it like this:
var url = "jdbc:mysql://localhost/records";
var sql = "SELECT * FROM patient_info WHERE name = '" + txt1.getText() + "'";
var found = false;
try( var con = DriverManager.getConnection( url, "root", "" );
var st = con.createStatement();
var rs = st.executeQuery( sql ) )
{
while( rs.next() )
{
var name = rs.getString( "name" );
txt2.setText( name );
System.out.println( "working" );
found = true;
}
if( !found )
{
txt2.setText( "no records" );
System.out.println( "no records" );
}
}
catch( SQLException e )
{
e.printStackTrace();
}
The DriverManager knows the driver even without loading the class, at least if your JDBC driver was written after the Stone Age. And the try-with-resources ensures that everything is properly closed when not longer needed.
You should do it as follows:
ResultSet rs = st.executeQuery(sql);
if (!rs.next()) {
txt2.setText("no records");
System.out.println("no records");
}
else {
do {
name = rs.getString("name");
txt2.setText(name);
System.out.println("working");
} while (rs.next());
}
Also, assuming there is only one record matching name from your sql query, a loop does not make sense i.e. you should do it as:
ResultSet rs = st.executeQuery(sql);
if (!rs.next()) {
txt2.setText("no records");
System.out.println("no records");
}
else {
name = rs.getString("name");
txt2.setText(name);
System.out.println("working");
}
Apart from this, given below are some important points you should always consider:
Use PreparedStatement instead of Statement to avoid SQL injection. Apart from saving your application from the attack of SQL injection, the use of PreparedStatement also helps you get rid of enclosing the strings in single quotes (as you have done in your sql query). Check this for more information.
You do not need Class.forName("com.mysql.jdbc.Driver"); when you use DriverManager.getConnection. Check this for more information.

How to hold MySQL query result in an int variable if possible

I want to know whether a table exist or not before creating another one is there any way of holding result in a variable after execution of command, i am using this code but it keeps giving only true even if table doesn't exists.
public static boolean checkBefore(){
boolean r = false;
try{
query = "SELECT COUNT(*)FROM information_schema.tables WHERE table_schema = 'sms' AND table_name = 'auth';";
con = connectsms();
st = con.createStatement();
ResultSet rs = st.executeQuery(query);
r = rs.next();
}catch(SQLException e){
JOptionPane.showMessageDialog(errorMsg,"Exeption Fount: "+e,"Opps! Exception Found in checkBefore()",JOptionPane.ERROR_MESSAGE);
}
System.out.println(r);
return r;
}
Every JDBC guide will show you that after executing a query, you need to call next() to advance to the next/first row, then call getter methods to retrieve the column values of that row.
Queries with aggregating functions (COUNT, MIN, MAX, etc) without a GROUP BY clause will always return exactly one row, so for those kinds of queries, you don't need to check the return value from next(). For pretty much all other queries, you do.
When calling JDBC methods that return resources, you should use try-with-resources to make sure those resource are cleaned up correctly.
Query string does not need to end with a ; semi-colon.
All that means that your code should be:
public static boolean checkBefore() {
String sql = "SELECT COUNT(*)" +
" FROM information_schema.tables" +
" WHERE table_schema = 'sms'" +
" AND table_name = 'auth'";
try ( Connection con = connectsms();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
) {
rs.next(); // exactly one row returned, so next() always returns true here
int count = rs.getInt(1); // get value from first column
System.out.println("count = " + count);
return (count != 0);
} catch (SQLException e) {
JOptionPane.showMessageDialog(errorMsg, "Exeption Fount: " + e,
"Opps! Exception Found in checkBefore()",
JOptionPane.ERROR_MESSAGE);
return 0;
}
}
Change r = rs.next(); to rs.next(); and then add r = rs.getInt(1) > 0; and it will work.
This is the query that worked for me:
SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'databse_name';
and the code that i am using and is working correct:
public static boolean checkBefore(){
boolean result = false;
try{
query = "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'sms'";
con = connectsms();
st = con.createStatement();
ResultSet rs = st.executeQuery(query);
result = rs.next();
System.out.println();
}catch(SQLException e){
JOptionPane.showMessageDialog(errorMsg,"Exeption Fount: "+e,"Opps! Exception Found in checkBefor()",JOptionPane.ERROR_MESSAGE);
}
try{
con.close();
}
catch(SQLException e){JOptionPane.showMessageDialog(errorMsg,"Exeption Fount: "+e,"unable to close connection",JOptionPane.ERROR_MESSAGE); }
System.out.println(result);
return result;
}

Can I use setMaxRows() with try-with-resouces?

I am attempting to write a method that selects 2 entries into an employee database and removes them (Based on a salary field), I am currently using a counter to accomplish this, however I tried using setMaxRows() so my result set would only have two entries, thus eliminating the need for the counter. I am using try-with-resources to create my statement and that seems to be causing an issue.
public void downSize(Connection con) {
String sql = "SELECT * FROM " + schemaName + "."+tableName+" WHERE EMPLOYEE_SALARY>200000";
try (
PreparedStatement statement = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = statement.executeQuery();
)
{
int counter = 0;
System.out.println("Now pruning workforce...");
while(rs.next() && counter<2) {
String name = rs.getString("EMPLOYEE_NAME");
rs.deleteRow();
counter++;
System.out.println(name+" was laid off.");
}
} catch(Exception e) {
e.printStackTrace();
System.out.print("Sql exception happened");
}
}

Get multiple result sets with JDBC doesn't work [duplicate]

This question already has answers here:
Execute "sp_msforeachdb" in a Java application
(3 answers)
Closed 5 years ago.
I should call stored procedure from the third party SQL Server data base (have rights for read only).
Also, when I tried to execute this procedure for example in DataGrip:
EXEC Web.example_procedure 2, 3, 4
I received two results:
firs:
<anonymous>
-----------
3
second:
column_1 | column_2
------------------
k1 | v1
k2 | v2
k3 | v3
...
I need a second table.
Now I'm doing the next due to this article
private static void executeStatement(Connection con) {
try {
String SQL = "EXEC Web.example_procedure 2, 3, 4";
Statement stmt = con.createStatement();
boolean results = stmt.execute(SQL);
int rsCount = 0;
//Loop through the available result sets.
do {
if (results) {
ResultSet rs = stmt.getResultSet();
rsCount++;
//Show data from the result set.
System.out.println("RESULT SET #" + rsCount);
while (rs.next()) {
// something will be here
}
rs.close();
}
results = stmt.getMoreResults();
} while (results);
stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Output is:
RESULT SET #1
In other words, I get only the first result.
How to get the second table?
can I modify SQL query? (Which will return only one table without
first int result)
JDBC?
Hibernate?
I will be glad to any working variant.
Update
Thanks to #MarkRotteveel and his answer - I solved the problem
String sql = "EXEC Web.example_procedure 2, 3, 4";
PreparedStatement stmt = con.prepareStatement(sql);
boolean result = stmt.execute();
while (true) {
if (result) {
ResultSet rs = stmt.getResultSet();
// in my case first table has only one column,
// and I need the second table, which has 9 columns
if (rs.getMetaData().getColumnCount() > 1) {
// go through the rows
while (rs.next()) {
// for example what we can do
rs.getMetaData().getColumnCount(); // return column count in the current result set
rs.getObject(int columnIndex); // get value for column index. Must be not greater than .getColumnCount()
}
}
} else {
int updateCount = stmt.getUpdateCount();
if (updateCount == -1) {
// no more results
break;
}
}
result = stmt.getMoreResults();
}
Use JDBC CallableStatement:
cstmt.registerOutParameter()
cstmt.getObject()
String sql = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall(sql);
//Bind IN parameter first, then bind OUT parameter
int empID = 102;
cstmt.setInt(1, empID); // This would set ID as 102
// Because second parameter is OUT so register it
cstmt.registerOutParameter(2, OracleTypes.CURSOR);
//Use execute method to run stored procedure.
System.out.println("Executing stored procedure..." );
cstmt.execute();
//Retrieve data
rs = (ResultSet) cstmt.getObject(1);
https://docs.oracle.com/cd/E17952_01/connector-j-en/connector-j-usagenotes-statements-callable.html
You can set the Resultset updateable to execute multiple command.
Statement stmt = conn1.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String insert1="insert into data values('******','*********')";
String insert2="insert into data values('*******','******')";
conn1.setAutoCommit(false);
ResultSet rs = stmt.executeQuery("select * from data");
rs.last();

How do you access the value of an SQL count () query in a Java program

I want to get to the value I am finding using the COUNT command of SQL. Normally I enter the column name I want to access into the getInt() getString() method, what do I do in this case when there is no specific column name.
I have used 'AS' in the same manner as is used to alias a table, I am not sure if this is going to work, I would think not.
Statement stmt3 = con.createStatement();
ResultSet rs3 = stmt3.executeQuery("SELECT COUNT(*) FROM "+lastTempTable+") AS count");
while(rs3.next()){
count = rs3.getInt("count");
}
Use aliases:
SELECT COUNT(*) AS total FROM ..
and then
rs3.getInt("total")
The answers provided by Bohzo and Brabster will obviously work, but you could also just use:
rs3.getInt(1);
to get the value in the first, and in your case, only column.
I would expect this query to work with your program:
"SELECT COUNT(*) AS count FROM "+lastTempTable+")"
(You need to alias the column, not the table)
I have done it this way (example):
String query="SELECT count(t1.id) from t1, t2 where t1.id=t2.id and t2.email='"r#r.com"'";
int count=0;
try {
ResultSet rs = DatabaseService.statementDataBase().executeQuery(query);
while(rs.next())
count=rs.getInt(1);
} catch (SQLException e) {
e.printStackTrace();
} finally {
//...
}
<%
try{
Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bala","bala","bala");
if(con == null) System.out.print("not connected");
Statement st = con.createStatement();
String myStatement = "select count(*) as total from locations";
ResultSet rs = st.executeQuery(myStatement);
int num = 0;
while(rs.next()){
num = (rs.getInt(1));
}
}
catch(Exception e){
System.out.println(e);
}
%>
Statement stmt3 = con.createStatement();
ResultSet rs3 = stmt3.executeQuery("SELECT COUNT(*) AS count FROM "+lastTempTable+" ;");
count = rs3.getInt("count");
It's similar to above but you can try like
public Integer count(String tableName) throws CrateException {
String query = String.format("Select count(*) as size from %s", tableName);
try (Statement s = connection.createStatement()) {
try (ResultSet resultSet = queryExecutor.executeQuery(s, query)) {
Preconditions.checkArgument(resultSet.next(), "Result set is empty");
return resultSet.getInt("size");
}
} catch (SQLException e) {
throw new CrateException(e);
}
}
}

Categories