JDBC Error when trying a parametric update - java

I'm trying to update the record in my MySql database using JDBC.
Here is the method:
public void updateGareCorse(CorrePer c) {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = DBConnectionPool.getConnection();
String sql = "update corre_per set gare_corse = ?\n"
+ " where codice_pilota = ? and anno = ?";
ps = con.prepareStatement(sql);
ps.setString(1, c.getGare_corse());
ps.setString(2, c.getCodice());
ps.setInt(3, c.getAnno());
System.out.println("QUERY:\nUPDATE corre_per SET gare_corse = " + c.getGare_corse()+" WHERE anno = "+ c.getAnno() +" AND codice_pilota = " + c.getCodice()+")");
int result = ps.executeUpdate(sql);
if (result > 0) {
System.out.println("Update OK");
} else {
System.out.println("Update NOT OK");
}
con.commit();
} catch (SQLException s) {
System.err.println(s.getMessage());
Utility.printSQLException(s);
} finally {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
DBConnectionPool.releaseConnection(con);
} catch (SQLException s) {
System.err.println(s.getMessage());
Utility.printSQLException(s);
}
}
}
CorrePer is a Java class that represents my CorrePer table and has variables that represent my CorrePer attributes and their getter and setter method.
Now, when I execute this method, Eclipse gives this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? where codice_pilota = ? and anno = ?' at line 1
Why the method doesn't work? Any help is much appreciated.
UPDATE: I tried to pass only one parameter at a time, with the others not being parametric, but already written in the query, like this:
String sql = "update corre_per set gare_corse = \"1-\"\n"
+ " where codice_pilota = \"TSU\" and anno = ?";
ps = con.prepareStatement(sql);
//ps.setString(1, c.getGare_corse());
//ps.setString(1, c.getCodice());
ps.setInt(1, c.getAnno());
Now it gives error only on the '?' at the end:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 2
So looks like there is a problem with the parameters association, but I'm not able to figure out it.

Here is your problem
int result = ps.executeUpdate(sql);
Just use (as you already set your parameter values)
int result = ps.executeUpdate();
Otherwise actual call is delegated to java.sql.Statement.executeUpdate(String) which perform SQL udpate as-is (without interpolation of arguments, so ? tokens in your parametrized query are not replaced with supplied values)

Related

How do I use SELECT LAST_INSERT_ID() without closing the connection [duplicate]

I want to INSERT a record in a database (which is Microsoft SQL Server in my case) using JDBC in Java. At the same time, I want to obtain the insert ID. How can I achieve this using JDBC API?
If it is an auto generated key, then you can use Statement#getGeneratedKeys() for this. You need to call it on the same Statement as the one being used for the INSERT. You first need to create the statement using Statement.RETURN_GENERATED_KEYS to notify the JDBC driver to return the keys.
Here's a basic example:
public void create(User user) throws SQLException {
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(SQL_INSERT,
Statement.RETURN_GENERATED_KEYS);
) {
statement.setString(1, user.getName());
statement.setString(2, user.getPassword());
statement.setString(3, user.getEmail());
// ...
int affectedRows = statement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
}
else {
throw new SQLException("Creating user failed, no ID obtained.");
}
}
}
}
Note that you're dependent on the JDBC driver as to whether it works. Currently, most of the last versions will work, but if I am correct, Oracle JDBC driver is still somewhat troublesome with this. MySQL and DB2 already supported it for ages. PostgreSQL started to support it not long ago. I can't comment about MSSQL as I've never used it.
For Oracle, you can invoke a CallableStatement with a RETURNING clause or a SELECT CURRVAL(sequencename) (or whatever DB-specific syntax to do so) directly after the INSERT in the same transaction to obtain the last generated key. See also this answer.
Create Generated Column
String generatedColumns[] = { "ID" };
Pass this geneated Column to your statement
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Use ResultSet object to fetch the GeneratedKeys on Statement
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
When encountering an 'Unsupported feature' error while using Statement.RETURN_GENERATED_KEYS, try this:
String[] returnId = { "BATCHID" };
String sql = "INSERT INTO BATCH (BATCHNAME) VALUES ('aaaaaaa')";
PreparedStatement statement = connection.prepareStatement(sql, returnId);
int affectedRows = statement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet rs = statement.getGeneratedKeys()) {
if (rs.next()) {
System.out.println(rs.getInt(1));
}
rs.close();
}
Where BATCHID is the auto generated id.
I'm hitting Microsoft SQL Server 2008 R2 from a single-threaded JDBC-based application and pulling back the last ID without using the RETURN_GENERATED_KEYS property or any PreparedStatement. Looks something like this:
private int insertQueryReturnInt(String SQLQy) {
ResultSet generatedKeys = null;
int generatedKey = -1;
try {
Statement statement = conn.createStatement();
statement.execute(SQLQy);
} catch (Exception e) {
errorDescription = "Failed to insert SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
try {
generatedKey = Integer.parseInt(readOneValue("SELECT ##IDENTITY"));
} catch (Exception e) {
errorDescription = "Failed to get ID of just-inserted SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
return generatedKey;
}
This blog post nicely isolates three main SQL Server "last ID" options:
http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the-sql-server/ - haven't needed the other two yet.
Instead of a comment, I just want to answer post.
Interface java.sql.PreparedStatement
columnIndexes « You can use prepareStatement function that accepts columnIndexes and SQL statement.
Where columnIndexes allowed constant flags are Statement.RETURN_GENERATED_KEYS1 or Statement.NO_GENERATED_KEYS[2], SQL statement that may contain one or more '?' IN parameter placeholders.
SYNTAX «
Connection.prepareStatement(String sql, int autoGeneratedKeys)
Connection.prepareStatement(String sql, int[] columnIndexes)
Example:
PreparedStatement pstmt =
conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « List out the columnNames like 'id', 'uniqueID', .... in the target table that contain the auto-generated keys that should be returned. The driver will ignore them if the SQL statement is not an INSERT statement.
SYNTAX «
Connection.prepareStatement(String sql, String[] columnNames)
Example:
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Full Example:
public static void insertAutoIncrement_SQL(String UserName, String Language, String Message) {
String DB_URL = "jdbc:mysql://localhost:3306/test", DB_User = "root", DB_Password = "";
String insertSQL = "INSERT INTO `unicodeinfo`( `UserName`, `Language`, `Message`) VALUES (?,?,?)";
//"INSERT INTO `unicodeinfo`(`id`, `UserName`, `Language`, `Message`) VALUES (?,?,?,?)";
int primkey = 0 ;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(DB_URL, DB_User, DB_Password);
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
pstmt.setString(1, UserName );
pstmt.setString(2, Language );
pstmt.setString(3, Message );
if (pstmt.executeUpdate() > 0) {
// Retrieves any auto-generated keys created as a result of executing this Statement object
java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys();
if ( generatedKeys.next() ) {
primkey = generatedKeys.getInt(1);
}
}
System.out.println("Record updated with id = "+primkey);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
I'm using SQLServer 2008, but I have a development limitation: I cannot use a new driver for it, I have to use "com.microsoft.jdbc.sqlserver.SQLServerDriver" (I cannot use "com.microsoft.sqlserver.jdbc.SQLServerDriver").
That's why the solution conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) threw a java.lang.AbstractMethodError for me.
In this situation, a possible solution I found is the old one suggested by Microsoft:
How To Retrieve ##IDENTITY Value Using JDBC
import java.sql.*;
import java.io.*;
public class IdentitySample
{
public static void main(String args[])
{
try
{
String URL = "jdbc:microsoft:sqlserver://yourServer:1433;databasename=pubs";
String userName = "yourUser";
String password = "yourPassword";
System.out.println( "Trying to connect to: " + URL);
//Register JDBC Driver
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
//Connect to SQL Server
Connection con = null;
con = DriverManager.getConnection(URL,userName,password);
System.out.println("Successfully connected to server");
//Create statement and Execute using either a stored procecure or batch statement
CallableStatement callstmt = null;
callstmt = con.prepareCall("INSERT INTO myIdentTable (col2) VALUES (?);SELECT ##IDENTITY");
callstmt.setString(1, "testInputBatch");
System.out.println("Batch statement successfully executed");
callstmt.execute();
int iUpdCount = callstmt.getUpdateCount();
boolean bMoreResults = true;
ResultSet rs = null;
int myIdentVal = -1; //to store the ##IDENTITY
//While there are still more results or update counts
//available, continue processing resultsets
while (bMoreResults || iUpdCount!=-1)
{
//NOTE: in order for output parameters to be available,
//all resultsets must be processed
rs = callstmt.getResultSet();
//if rs is not null, we know we can get the results from the SELECT ##IDENTITY
if (rs != null)
{
rs.next();
myIdentVal = rs.getInt(1);
}
//Do something with the results here (not shown)
//get the next resultset, if there is one
//this call also implicitly closes the previously obtained ResultSet
bMoreResults = callstmt.getMoreResults();
iUpdCount = callstmt.getUpdateCount();
}
System.out.println( "##IDENTITY is: " + myIdentVal);
//Close statement and connection
callstmt.close();
con.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
try
{
System.out.println("Press any key to quit...");
System.in.read();
}
catch (Exception e)
{
}
}
}
This solution worked for me!
I hope this helps!
You can use following java code to get new inserted id.
ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, quizid);
ps.setInt(2, userid);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
lastInsertId = rs.getInt(1);
}
It is possible to use it with normal Statement's as well (not just PreparedStatement)
Statement statement = conn.createStatement();
int updateCount = statement.executeUpdate("insert into x...)", Statement.RETURN_GENERATED_KEYS);
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
return generatedKeys.getLong(1);
}
else {
throw new SQLException("Creating failed, no ID obtained.");
}
}
Most others have suggested to use JDBC API for this, but personally, I find it quite painful to do with most drivers. When in fact, you can just use a native T-SQL feature, the OUTPUT clause:
try (
Statement s = c.createStatement();
ResultSet rs = s.executeQuery(
"""
INSERT INTO t (a, b)
OUTPUT id
VALUES (1, 2)
"""
);
) {
while (rs.next())
System.out.println("ID = " + rs.getLong(1));
}
This is the simplest solution for SQL Server as well as a few other SQL dialects (e.g. Firebird, MariaDB, PostgreSQL, where you'd use RETURNING instead of OUTPUT).
I've blogged about this topic more in detail here.
With Hibernate's NativeQuery, you need to return a ResultList instead of a SingleResult, because Hibernate modifies a native query
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
like
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
if you try to get a single result, which causes most databases (at least PostgreSQL) to throw a syntax error. Afterwards, you may fetch the resulting id from the list (which usually contains exactly one item).
In my case ->
ConnectionClass objConnectionClass=new ConnectionClass();
con=objConnectionClass.getDataBaseConnection();
pstmtGetAdd=con.prepareStatement(SQL_INSERT_ADDRESS_QUERY,Statement.RETURN_GENERATED_KEYS);
pstmtGetAdd.setString(1, objRegisterVO.getAddress());
pstmtGetAdd.setInt(2, Integer.parseInt(objRegisterVO.getCityId()));
int addId=pstmtGetAdd.executeUpdate();
if(addId>0)
{
ResultSet rsVal=pstmtGetAdd.getGeneratedKeys();
rsVal.next();
addId=rsVal.getInt(1);
}
If you are using Spring JDBC, you can use Spring's GeneratedKeyHolder class to get the inserted ID.
See this answer...
How to get inserted id using Spring Jdbctemplate.update(String sql, obj...args)
If you are using JDBC (tested with MySQL) and you just want the last inserted ID, there is an easy way to get it. The method I'm using is the following:
public static Integer insert(ConnectionImpl connection, String insertQuery){
Integer lastInsertId = -1;
try{
final PreparedStatement ps = connection.prepareStatement(insertQuery);
ps.executeUpdate(insertQuery);
final com.mysql.jdbc.PreparedStatement psFinal = (com.mysql.jdbc.PreparedStatement) ps;
lastInsertId = (int) psFinal.getLastInsertID();
connection.close();
} catch(SQLException ex){
System.err.println("Error: "+ex);
}
return lastInsertId;
}
Also, (and just in case) the method to get the ConnectionImpl is the following:
public static ConnectionImpl getConnectionImpl(){
ConnectionImpl conexion = null;
final String dbName = "database_name";
final String dbPort = "3306";
final String dbIPAddress = "127.0.0.1";
final String connectionPath = "jdbc:mysql://"+dbIPAddress+":"+dbPort+"/"+dbName+"?autoReconnect=true&useSSL=false";
final String dbUser = "database_user";
final String dbPassword = "database_password";
try{
conexion = (ConnectionImpl) DriverManager.getConnection(connectionPath, dbUser, dbPassword);
}catch(SQLException e){
System.err.println(e);
}
return conexion;
}
Remember to add the connector/J to the project referenced libraries.
In my case, the connector/J version is the 5.1.42. Maybe you will have to apply some changes to the connectionPath if you want to use a more modern version of the connector/J such as with the version 8.0.28.
In the file, remember to import the following resources:
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.mysql.jdbc.ConnectionImpl;
Hope this will be helpful.
Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret = st.execute();

java.sql.SQLException: Column index out range, (int) < 1 [duplicate]

I want to INSERT a record in a database (which is Microsoft SQL Server in my case) using JDBC in Java. At the same time, I want to obtain the insert ID. How can I achieve this using JDBC API?
If it is an auto generated key, then you can use Statement#getGeneratedKeys() for this. You need to call it on the same Statement as the one being used for the INSERT. You first need to create the statement using Statement.RETURN_GENERATED_KEYS to notify the JDBC driver to return the keys.
Here's a basic example:
public void create(User user) throws SQLException {
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(SQL_INSERT,
Statement.RETURN_GENERATED_KEYS);
) {
statement.setString(1, user.getName());
statement.setString(2, user.getPassword());
statement.setString(3, user.getEmail());
// ...
int affectedRows = statement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
}
else {
throw new SQLException("Creating user failed, no ID obtained.");
}
}
}
}
Note that you're dependent on the JDBC driver as to whether it works. Currently, most of the last versions will work, but if I am correct, Oracle JDBC driver is still somewhat troublesome with this. MySQL and DB2 already supported it for ages. PostgreSQL started to support it not long ago. I can't comment about MSSQL as I've never used it.
For Oracle, you can invoke a CallableStatement with a RETURNING clause or a SELECT CURRVAL(sequencename) (or whatever DB-specific syntax to do so) directly after the INSERT in the same transaction to obtain the last generated key. See also this answer.
Create Generated Column
String generatedColumns[] = { "ID" };
Pass this geneated Column to your statement
PreparedStatement stmtInsert = conn.prepareStatement(insertSQL, generatedColumns);
Use ResultSet object to fetch the GeneratedKeys on Statement
ResultSet rs = stmtInsert.getGeneratedKeys();
if (rs.next()) {
long id = rs.getLong(1);
System.out.println("Inserted ID -" + id); // display inserted record
}
When encountering an 'Unsupported feature' error while using Statement.RETURN_GENERATED_KEYS, try this:
String[] returnId = { "BATCHID" };
String sql = "INSERT INTO BATCH (BATCHNAME) VALUES ('aaaaaaa')";
PreparedStatement statement = connection.prepareStatement(sql, returnId);
int affectedRows = statement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
try (ResultSet rs = statement.getGeneratedKeys()) {
if (rs.next()) {
System.out.println(rs.getInt(1));
}
rs.close();
}
Where BATCHID is the auto generated id.
I'm hitting Microsoft SQL Server 2008 R2 from a single-threaded JDBC-based application and pulling back the last ID without using the RETURN_GENERATED_KEYS property or any PreparedStatement. Looks something like this:
private int insertQueryReturnInt(String SQLQy) {
ResultSet generatedKeys = null;
int generatedKey = -1;
try {
Statement statement = conn.createStatement();
statement.execute(SQLQy);
} catch (Exception e) {
errorDescription = "Failed to insert SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
try {
generatedKey = Integer.parseInt(readOneValue("SELECT ##IDENTITY"));
} catch (Exception e) {
errorDescription = "Failed to get ID of just-inserted SQL query: " + SQLQy + "( " + e.toString() + ")";
return -1;
}
return generatedKey;
}
This blog post nicely isolates three main SQL Server "last ID" options:
http://msjawahar.wordpress.com/2008/01/25/how-to-find-the-last-identity-value-inserted-in-the-sql-server/ - haven't needed the other two yet.
Instead of a comment, I just want to answer post.
Interface java.sql.PreparedStatement
columnIndexes « You can use prepareStatement function that accepts columnIndexes and SQL statement.
Where columnIndexes allowed constant flags are Statement.RETURN_GENERATED_KEYS1 or Statement.NO_GENERATED_KEYS[2], SQL statement that may contain one or more '?' IN parameter placeholders.
SYNTAX «
Connection.prepareStatement(String sql, int autoGeneratedKeys)
Connection.prepareStatement(String sql, int[] columnIndexes)
Example:
PreparedStatement pstmt =
conn.prepareStatement( insertSQL, Statement.RETURN_GENERATED_KEYS );
columnNames « List out the columnNames like 'id', 'uniqueID', .... in the target table that contain the auto-generated keys that should be returned. The driver will ignore them if the SQL statement is not an INSERT statement.
SYNTAX «
Connection.prepareStatement(String sql, String[] columnNames)
Example:
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
Full Example:
public static void insertAutoIncrement_SQL(String UserName, String Language, String Message) {
String DB_URL = "jdbc:mysql://localhost:3306/test", DB_User = "root", DB_Password = "";
String insertSQL = "INSERT INTO `unicodeinfo`( `UserName`, `Language`, `Message`) VALUES (?,?,?)";
//"INSERT INTO `unicodeinfo`(`id`, `UserName`, `Language`, `Message`) VALUES (?,?,?,?)";
int primkey = 0 ;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(DB_URL, DB_User, DB_Password);
String columnNames[] = new String[] { "id" };
PreparedStatement pstmt = conn.prepareStatement( insertSQL, columnNames );
pstmt.setString(1, UserName );
pstmt.setString(2, Language );
pstmt.setString(3, Message );
if (pstmt.executeUpdate() > 0) {
// Retrieves any auto-generated keys created as a result of executing this Statement object
java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys();
if ( generatedKeys.next() ) {
primkey = generatedKeys.getInt(1);
}
}
System.out.println("Record updated with id = "+primkey);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
I'm using SQLServer 2008, but I have a development limitation: I cannot use a new driver for it, I have to use "com.microsoft.jdbc.sqlserver.SQLServerDriver" (I cannot use "com.microsoft.sqlserver.jdbc.SQLServerDriver").
That's why the solution conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) threw a java.lang.AbstractMethodError for me.
In this situation, a possible solution I found is the old one suggested by Microsoft:
How To Retrieve ##IDENTITY Value Using JDBC
import java.sql.*;
import java.io.*;
public class IdentitySample
{
public static void main(String args[])
{
try
{
String URL = "jdbc:microsoft:sqlserver://yourServer:1433;databasename=pubs";
String userName = "yourUser";
String password = "yourPassword";
System.out.println( "Trying to connect to: " + URL);
//Register JDBC Driver
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
//Connect to SQL Server
Connection con = null;
con = DriverManager.getConnection(URL,userName,password);
System.out.println("Successfully connected to server");
//Create statement and Execute using either a stored procecure or batch statement
CallableStatement callstmt = null;
callstmt = con.prepareCall("INSERT INTO myIdentTable (col2) VALUES (?);SELECT ##IDENTITY");
callstmt.setString(1, "testInputBatch");
System.out.println("Batch statement successfully executed");
callstmt.execute();
int iUpdCount = callstmt.getUpdateCount();
boolean bMoreResults = true;
ResultSet rs = null;
int myIdentVal = -1; //to store the ##IDENTITY
//While there are still more results or update counts
//available, continue processing resultsets
while (bMoreResults || iUpdCount!=-1)
{
//NOTE: in order for output parameters to be available,
//all resultsets must be processed
rs = callstmt.getResultSet();
//if rs is not null, we know we can get the results from the SELECT ##IDENTITY
if (rs != null)
{
rs.next();
myIdentVal = rs.getInt(1);
}
//Do something with the results here (not shown)
//get the next resultset, if there is one
//this call also implicitly closes the previously obtained ResultSet
bMoreResults = callstmt.getMoreResults();
iUpdCount = callstmt.getUpdateCount();
}
System.out.println( "##IDENTITY is: " + myIdentVal);
//Close statement and connection
callstmt.close();
con.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
try
{
System.out.println("Press any key to quit...");
System.in.read();
}
catch (Exception e)
{
}
}
}
This solution worked for me!
I hope this helps!
You can use following java code to get new inserted id.
ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, quizid);
ps.setInt(2, userid);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
lastInsertId = rs.getInt(1);
}
It is possible to use it with normal Statement's as well (not just PreparedStatement)
Statement statement = conn.createStatement();
int updateCount = statement.executeUpdate("insert into x...)", Statement.RETURN_GENERATED_KEYS);
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
return generatedKeys.getLong(1);
}
else {
throw new SQLException("Creating failed, no ID obtained.");
}
}
Most others have suggested to use JDBC API for this, but personally, I find it quite painful to do with most drivers. When in fact, you can just use a native T-SQL feature, the OUTPUT clause:
try (
Statement s = c.createStatement();
ResultSet rs = s.executeQuery(
"""
INSERT INTO t (a, b)
OUTPUT id
VALUES (1, 2)
"""
);
) {
while (rs.next())
System.out.println("ID = " + rs.getLong(1));
}
This is the simplest solution for SQL Server as well as a few other SQL dialects (e.g. Firebird, MariaDB, PostgreSQL, where you'd use RETURNING instead of OUTPUT).
I've blogged about this topic more in detail here.
With Hibernate's NativeQuery, you need to return a ResultList instead of a SingleResult, because Hibernate modifies a native query
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id
like
INSERT INTO bla (a,b) VALUES (2,3) RETURNING id LIMIT 1
if you try to get a single result, which causes most databases (at least PostgreSQL) to throw a syntax error. Afterwards, you may fetch the resulting id from the list (which usually contains exactly one item).
In my case ->
ConnectionClass objConnectionClass=new ConnectionClass();
con=objConnectionClass.getDataBaseConnection();
pstmtGetAdd=con.prepareStatement(SQL_INSERT_ADDRESS_QUERY,Statement.RETURN_GENERATED_KEYS);
pstmtGetAdd.setString(1, objRegisterVO.getAddress());
pstmtGetAdd.setInt(2, Integer.parseInt(objRegisterVO.getCityId()));
int addId=pstmtGetAdd.executeUpdate();
if(addId>0)
{
ResultSet rsVal=pstmtGetAdd.getGeneratedKeys();
rsVal.next();
addId=rsVal.getInt(1);
}
If you are using Spring JDBC, you can use Spring's GeneratedKeyHolder class to get the inserted ID.
See this answer...
How to get inserted id using Spring Jdbctemplate.update(String sql, obj...args)
If you are using JDBC (tested with MySQL) and you just want the last inserted ID, there is an easy way to get it. The method I'm using is the following:
public static Integer insert(ConnectionImpl connection, String insertQuery){
Integer lastInsertId = -1;
try{
final PreparedStatement ps = connection.prepareStatement(insertQuery);
ps.executeUpdate(insertQuery);
final com.mysql.jdbc.PreparedStatement psFinal = (com.mysql.jdbc.PreparedStatement) ps;
lastInsertId = (int) psFinal.getLastInsertID();
connection.close();
} catch(SQLException ex){
System.err.println("Error: "+ex);
}
return lastInsertId;
}
Also, (and just in case) the method to get the ConnectionImpl is the following:
public static ConnectionImpl getConnectionImpl(){
ConnectionImpl conexion = null;
final String dbName = "database_name";
final String dbPort = "3306";
final String dbIPAddress = "127.0.0.1";
final String connectionPath = "jdbc:mysql://"+dbIPAddress+":"+dbPort+"/"+dbName+"?autoReconnect=true&useSSL=false";
final String dbUser = "database_user";
final String dbPassword = "database_password";
try{
conexion = (ConnectionImpl) DriverManager.getConnection(connectionPath, dbUser, dbPassword);
}catch(SQLException e){
System.err.println(e);
}
return conexion;
}
Remember to add the connector/J to the project referenced libraries.
In my case, the connector/J version is the 5.1.42. Maybe you will have to apply some changes to the connectionPath if you want to use a more modern version of the connector/J such as with the version 8.0.28.
In the file, remember to import the following resources:
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.mysql.jdbc.ConnectionImpl;
Hope this will be helpful.
Connection cn = DriverManager.getConnection("Host","user","pass");
Statement st = cn.createStatement("Ur Requet Sql");
int ret = st.execute();

setString for prepared statement not working

I am trying to use the setString(index, parameter) method for Prepared Statements in order to create a ResultSet but it doesn't seem to be inserting properly. I know the query is correct because I use the same one (minus the need for the setString) in a later else. Here is the code I currently have:
**From what I understand, the ps.setString(1, "'%" + committeeCode + "%'"); is supposed to replace the ? in the query but my output says otherwise. Any help is appreciated.
public String getUpcomingEvents(String committeeCode) throws SQLException{
Context ctx = null;
DataSource ds = null;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
StringBuilder htmlBuilder = new StringBuilder();
String html = "";
try {
ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:ConnectDaily");
conn = ds.getConnection();
if(committeeCode != null){
//get all events
String queryStatement = "SELECT " +
.......
"WHERE c.calendar_id = ci.calendar_id AND c.short_name LIKE ? " +
"AND ci.style_id = 0 " +
"AND ci.starting_date > to_char(sysdate-1, 'J') " +
"AND ci.item_type_id = cit.item_type_id " +
"ORDER BY to_date(to_char(ci.starting_date), 'J')";
ps = conn.prepareStatement(queryStatement);
ps.setString(1, "'%" + committeeCode + "%'");
System.out.println(queryStatement);
rs = ps.executeQuery();
if (rs != null){
while(rs.next()){
String com = rs.getString("name");
String comID = rs.getString("short_name");
String startTime = rs.getString("starting_time");
String endTime = rs.getString("ending_time");
String name = rs.getString("contact_name");
String desc = rs.getString("description");
String info = rs.getString("contact_info");
String date = rs.getString("directory");
htmlBuilder.append("<li><a href='?com="+committeeCode+"&directory=2014-09-10'>"+com+" - "+ date +" - "+startTime+" - "+endTime+"</a> <!-- Link/title/date/start-end time --><br>");
htmlBuilder.append("<strong>Location: </strong>"+comID+"<br>");
htmlBuilder.append("<strong>Dial-In:</strong>"+com+"<br>");
htmlBuilder.append("<strong>Part. Code:</strong>"+info+"<br>");
htmlBuilder.append("<a href='http://nyiso.webex.com'>Take me to WebEx</a>");
htmlBuilder.append("</li>");
}
}
html = htmlBuilder.toString();
.
.
.
}catch (NamingException e) {
e.printStackTrace();
//log error and send error email
} catch (SQLException e) {
e.printStackTrace();
//log error and send error email
}finally{
//close all resources here
ps.close();
rs.close();
conn.close();
}
return html;
}
}
Output
14:18:22,979 INFO [STDOUT] SELECT to_char(to_date(to_char(ci.starting_date), 'J'),'mm/dd/yyyy') as start_date, to_char(to_date(to_char(ci.ending_date), 'J'),'mm/dd/yyyy') as end_date, to_char(to_date(to_char(ci.starting_date), 'J'),'yyyy-mm-dd') as directory, ci.starting_time, ci.ending_time, ci.description, cit.description as location, c.name, c.short_name, ci.add_info_url, ci.contact_name, ci.contact_info FROM calitem ci, calendar c, calitemtypes cit WHERE c.calendar_id = ci.calendar_id AND c.short_name LIKE ? AND ci.style_id = 0 AND ci.starting_date > to_char(sysdate-1, 'J') AND ci.item_type_id = cit.item_type_id ORDER BY to_date(to_char(ci.starting_date), 'J')
There is no need for the quotes in setString:
ps.setString(1, "%" + committeeCode + "%");
This method will bind the specified String to the first parameter. It will not change the original query String saved in queryStatement.
The placeholder remains as part of the SQL text.
The bind value is passed when the statement is executed; the actual SQL text is not modified. (This is one of the big advantages of prepared statements: the same exact SQL text is reused, and we avoid the overhead of a hard parse.
Also note that you are including single quotes within the value, which is a bit odd.
If the bind placeholder were to be replaced in the SQL text, assuming committeeCode contains foo, the equivalent SQL text would be:
AND c.short_name LIKE '''%foo%'''
which will match only c.short_name values that begin and end with a single quote, and contain the string foo.
(This looks more like Oracle SQL syntax than it does MySQL.)
As we know that in setString we can pass string value only, So even if we write the code like this:
String param="'%"+committeeCode+"%'";
And if you print the value of param it will throw error, Hence you cannot use it as well in prepared statement.
You need to modify modify it little bit as:
String param="%"+committeeCode+"%";(Simpler one, other way can be used)
ps.setString(1,param);

Java JDBC Incorrect Syntax Error

I have this method to load the objects, however when I am running the sql code it is giving me a Syntax error.
public void loadObjects() {
Statement s = setConnection();
// Add Administrators
try {
ResultSet r = s.executeQuery("SELECT * FROM Administrator;");
while (r.next()) {
Administrator getUser = new Administrator();
getUser.ID = r.getString(2);
ResultSet r2 = s.executeQuery("SELECT * FROM Userx WHERE ID= {" + getUser.ID + "};");
getUser.name = r2.getString(2);
getUser.surname = r2.getString(3);
getUser.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(getUser);
}
} catch (Exception e) {
System.out.println(e);
}
}
I have tried inserting the curly braces as stated in other questions, but I am either doing it wrong or it doesn't work.
This method should be able to load all administrators but I believe it is only inserting half of the ID.
The ID that it gets, consists of numbers and char; example "26315G"
the Error -
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '26315'.
Edit -
private java.sql.Connection setConnection(){
java.sql.Connection con = null;
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://" + host + ";DatabaseName=" + database + ";integratedSecurity=true;";
con = DriverManager.getConnection(url, username, password);
} catch(Exception e) {
System.out.println(e);
}
return con;
}
public void loadObjects() {
java.sql.Connection con = setConnection();
// Add Administrators
try {
PreparedStatement sql = con.prepareStatement("SELECT * FROM Administrator");
ResultSet rs = sql.executeQuery();
while (rs.next()) {
Administrator getUser = new Administrator();
getUser.ID = rs.getString(2);
PreparedStatement sql2 = con.prepareStatement("SELECT * FROM Userx WHERE ID=?");
sql2.setString(1, getUser.ID);
ResultSet r2 = sql2.executeQuery();
getUser.name = r2.getString(2);
getUser.surname = r2.getString(3);
getUser.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(getUser);
}
} catch (Exception e) {
System.out.println(e);
}
}
Actually it is not the way to do that in JDBC. That way, even if you sort your syntax error, your code is prone to sql injection attacks.
The right way would be:
// Let's say your user id is an integer
PreparedStatement stmt = connection.prepareStatement("select * from userx where id=?");
stmt.setInt(1, getUser.ID);
ResultSet rs = stmt.executeQuery();
This way you are guarded against any attempt to inject SQL in your application request parameters
First of all: if you use concurrently result-sets, you must use separate statements for each one of them (you can not share Statement s between two r and r2). And more, you lack r2.next() before reading from it.
On the other hand: it would be much more effective to use PreparedStatement in the loop that to rewrite the query all the time.
So I'd go for something like this:
public void loadObjects() {
try (
Statement st = getConnection().createStatement();
//- As you read (later) only id, then why to use '*' in this query? It only takes up resources.
ResultSet rs = st.executeQuery("SELECT id FROM Administrator");
PreparedStatement ps = getConnection().prepareStatement("SELECT * FROM Userx WHERE ID = ?");
ResultSet r2 = null;
) {
while (rs.next()) {
Administrator user = new Administrator();
user.ID = rs.getString("id");
ps.setInt(1, user.ID);
r2 = ps.executeQuery();
if (r2.next()) {
user.name = r2.getString(2);
user.surname = r2.getString(3);
user.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(user);
}
else {
System.out.println("User with ID=" + user.ID + " was not found.");
}
}
}
catch (Exception x) {
x.printStacktrace();
}
}
Please note use of Java7 auto-close feature (you didn't close resources in you code). And last note: until you are not separating statements in your queries, as to JDBC documentation, you should not place ';' at the end of statements (in all cases you shouldn't place ';' as the last character in you query string).
You should not use {} and you should not append parameters into a SQL query like this.
Remove the curly braces and use PreparedStatement instead.
see http://www.unixwiz.net/techtips/sql-injection.html

How to create Java method to count rows in Oracle table

I want to create Java method which can count the rows in Oracle table. So far I made this:
public int CheckDataDB(String DBtablename, String DBArgument) throws SQLException {
System.out.println("SessionHandle CheckUserDB:"+DBArgument);
int count;
String SQLStatement = null;
if (ds == null) {
throw new SQLException();
}
Connection conn = ds.getConnection();
if (conn == null) {
throw new SQLException();
}
PreparedStatement ps = null;
try {
conn.setAutoCommit(false);
boolean committed = false;
try {
SQLStatement = "SELECT count(*) FROM ? WHERE USERSTATUS = ?";
ps = conn.prepareStatement(SQLStatement);
ps.setString(1, DBtablename);
ps.setString(2, DBArgument);
ResultSet result = ps.executeQuery();
if (result.next()) {
count = result.getString("Passwd");
}
conn.commit();
committed = true;
} finally {
if (!committed) {
conn.rollback();
}
}
} finally {
/* Release the resources */
ps.close();
conn.close();
}
return count;
}
I want to use for different tables. This is the problem that I cannot solve:
count = result.getString("row");
Can you help me to solve the problem?
count = result.getInt(1);
This is needed, because count is int. And you can specify the index of the row returned by the query, you don't need to access it by name.
But you could also do:
count = result.getInt("count(*)");
This should do it:
count = result.getInt("count(*)");
You need to use the same name as you specified in your query to get the value. You could also make your
count = result.getString("row");
work by changing your query to
SQLStatement = "SELECT count(*) as row FROM ? WHERE USERSTATUS = ?";
You cannot use bind variable in place of a database object in an SQL query, can you? It can only be used for parameter binding.
Try this instead,
"SELECT count(*) as row_count FROM " + DBtablename + " WHERE USERSTATUS = ?";
This could be vulnerable to SQL Injection so you might want to check that DBtablename parameter is a valid database object name (i.e. at most 30 bytes long without spaces, and contains only valid chars for database object identifiers).
count = result.getInt("row_count");

Categories