Related
Two tables are present in the database, one is Student table with columns roll_no(PK), name, grade and DOB, another table StudentLeft with columns roll_no, name, grade and leaving_date.
I want to delete the record of the student from Student table whose roll no is entered by the user, and add the roll no, name, grade and leaving_date (the date when the record is deleted and added to the table) to StudentLeft table.
This is my method.
public static void main(String[] args) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null, preparedStatement1 = null, preparedStatement2 = null;
ResultSet resultSet = null;
String selectQuery = "", updateQuery = "", deleteQuery = "";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
connection = dataSource.getConnection();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (SQLException e) {
e.printStackTrace();
}
int rollNo = Integer.parseInt(args[0]);
try {
selectQuery = "SELECT name, grade FROM Student WHERE roll_no = ?";
updateQuery = "INSERT INTO StudentLog values WHERE roll_no = ?, name = ?, standard = ?";
deleteQuery = "DELETE Student WHERE roll_no = ?";
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(selectQuery);
preparedStatement.setInt(1, rollNo);
resultSet = preparedStatement.executeQuery();
preparedStatement1 = connection.prepareStatement(updateQuery);
preparedStatement1.setInt(1, rollNo);
while (resultSet.next()) {
String name = resultSet.getString("name");
String grade = resultSet.getString("grade");
preparedStatement1.setString(2, name);
preparedStatement1.setString(3, grade);
preparedStatement1.addBatch();
}
preparedStatement1.executeBatch();
preparedStatement2 = connection.prepareStatement(deleteQuery);
preparedStatement.setInt(1, rollNo);
connection.commit();
}
catch (SQLException e) {
e.printStackTrace();
}
try {
if (!preparedStatement.isClosed() || !preparedStatement1.isClosed() || !preparedStatement2.isClosed()) {
preparedStatement.close();
preparedStatement1.close();
preparedStatement2.close();
}
if (!connection.isClosed())
connection.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
These are the errors.
java.sql.BatchUpdateException: ORA-00936: missing expression
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10500)
at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:230)
at Q3.main(Q3.java:48)
Exception in thread "main" java.lang.NullPointerException
at Q3.main(Q3.java:62)
I am using oracle 11g express database.
The code you've written can be simplified quite a bit:
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
return;
}
int rollNo = Integer.parseInt(args[0]);
try (Connection connection = dataSource.getConnection()) {
connection.setAutoCommit(false);
String transferStatement = "INSERT INTO StudentLog (roll_no, name, standard, leaving_date) " +
"SELECT roll_no, name, standard, SYSDATE FROM Student WHERE roll_no = ?";
try (PreparedStatement stmt = connection.prepareStatement(transferStatement)) {
stmt.setInt(1, rollNo);
stmt.executeUpdate();
}
String deleteStatement = "DELETE FROM Student WHERE roll_no = ?";
try (PreparedStatement stmt = connection.prepareStatement(deleteStatement)) {
stmt.setInt(1, rollNo);
stmt.executeUpdate();
}
connection.commit();
}
catch (SQLException e) {
e.printStackTrace();
}
}
I've used try-with-resources statements, which simplifies the clean-up of connections and prepared statements: the connection and statements will get closed when the code inside the try (...) block finishes executing.
Transferring data from the Student table to the StudentLog table can be done in one go with an INSERT INTO ... SELECT statement. This statement doesn't return any result set: there's nothing to iterate through, we just execute it and the row gets inserted.
The DELETE statement is similar: it too returns no result set. I've added the keyword FROM to it out of convention more than anything else: as pointed out on another answer, FROM is optional.
I've also moved the catch (SQLException e) block to the end: that will handle all SQLExceptions generated when connecting to the database or executing either of the prepared statements.
I've kept the code that attempts to load the Oracle database driver class, but added a return statement in the catch block: if there's an exception, the driver isn't on the classpath and connecting to the database is guaranteed to fail so we may as well stop. However, for recent versions of the Oracle driver you don't need this check. Experiment with it: see if the code works without this check and if so, remove it.
Shouldn't your query be
DELETE FROM Student WHERE roll_no = ?
instead of
DELETE Student WHERE roll_no = ?
Your DELETE code used the wrong prepared statement, missing an execute.
It is advisable to use try-with-resources as below, for the automatic closing,
even on return or exception. (It also takes care of variable scopes.)
public static void main(String[] args) throws SQLException {
int rollNo = Integer.parseInt(args[0]);
// Better statements possible.
final String selectQuery = "SELECT name, grade FROM Student WHERE roll_no = ?";
final String updateQuery =
"INSERT INTO StudentLog VALUES WHERE roll_no = ?, name = ?, standard = ?";
final String deleteQuery = "DELETE FROM Student WHERE roll_no = ?";
try { // Check whether you need this. It is for the old discovery mechanism.
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch (ClassNotFoundException e) {
throw new IllegalStateException("Database driver not provided", e);
}
try (Connection connection = dataSource.getConnection()) {
connection.setAutoCommit(false);
try (PreparedStatement preparedStatement =
connection.prepareStatement(selectQuery)) {
preparedStatement.setInt(1, rollNo);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
try (PreparedStatement preparedStatement1 =
connection.prepareStatement(updateQuery)) {
preparedStatement1.setInt(1, rollNo);
while (resultSet.next()) {
String name = resultSet.getString("name");
String grade = resultSet.getString("grade");
preparedStatement1.setString(2, name);
preparedStatement1.setString(3, grade);
preparedStatement1.addBatch();
}
preparedStatement1.executeBatch();
}
}
}
try (PreparedStatement preparedStatement2 =
connection.prepareStatement(deleteQuery)) {
preparedStatement2.setInt(1, rollNo); // NOT preparedStatement
preparedStatement2.executeUpdate();
}
connection.commit();
}
}
Then one should SELECT+INSERT to the database, using one statement (INSERT SELECT).
The SQL of the StudentLog is a bit incomprehensible to me, but a nice INSERT would be:
INSERT INTO StudentLog VALUES(roll_no, name, standard)
SELECT roll_no, name, grade
FROM Student
WHERE roll_no = ?
Removing the need java nesting of database accesses.
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();
So, I'm getting the error in the title while executing the below process and I really don't know what can be wrong.
What I'm doing is trying to bring some data from a database to create an object and fill and arraylist with several of it's objects, if not found should throw an exceptio
public ArrayList<Caso> buscarCasosPorJuez(String cedula) throws java.sql.SQLException,Exception{
java.sql.ResultSet rs;
String sql;
Caso caso;
ArrayList<Caso> casos = new ArrayList();
sql="SELECT * "+
"FROM tcaso "+
"WHERE CedulaJ='"+cedula+"';";
Conector.getConector().ejecutarSQL(sql);
rs = Conector.getConector().ejecutarSQL(sql,true);
while (rs.next()){
caso = new Caso(
rs.getInt("NumCaso"),
rs.getString("DescripcionCaso"),
rs.getString("EstadoCaso"),
rs.getDate("FechaCreacion").toLocalDate(),
persona.buscarJuezPorCedula(rs.getString("CedulaJ")),
persona.buscarQuerellante(rs.getString("CedulaQ"))
);
casos.add(caso);
}
rs.close();
return casos;
}
Below are the two methods the "New Caso" is calling on the two final lines.
public Juez buscarJuezPorCedula(String cedula) throws java.sql.SQLException,Exception{
Juez juez = null;
java.sql.ResultSet rs;
String sql;
sql = "SELECT Sala,Usuario,Clave,NombreJ,ApellidosJ,TelefonoJ,CedulaJ "+
"FROM tjuez "+
"WHERE CedulaJ='"+cedula+"';";
rs = Conector.getConector().ejecutarSQL(sql,false);
if (rs.next()){
juez = new Juez(
rs.getInt("Sala"),
rs.getString("Usuario"),
rs.getString("Clave"),
rs.getString("NombreJ"),
rs.getString("ApellidosJ"),
rs.getString("TelefonoJ"),
rs.getString("CedulaJ"));
} else {
throw new Exception ("Persona no encontrada intentelo de nuevo.");
}
rs.close();
return juez;
}
public Querellante buscarQuerellante(String cedula) throws java.sql.SQLException,Exception{
Querellante querellante = null;
java.sql.ResultSet rs;
String sql;
sql = "SELECT DireccionQ,NombreQ,ApellidosQ,TelefonoQ,CedulaQ "+
"FROM tquerellante "+
"WHERE CedulaQ='"+cedula+"';";
rs = Conector.getConector().ejecutarSQL(sql,true);
if (rs.next()){
querellante = new Querellante(
rs.getString("DireccionQ"),
rs.getString("NombreQ"),
rs.getString("ApellidosQ"),
rs.getString("TelefonoQ"),
rs.getString("CedulaQ"));
} else {
throw new Exception ("Persona no encontrada intentelo de nuevo.");
}
rs.close();
return querellante;
}
Thanks for all the help you can provide.
I suspect you are closing the Statement object in ejucutarSQL(), which closes all ResultSets derived from it.
You can't actually write all-purpose SQL-executing methods like that, at least not without using CachedRowSet, which costs memory.
You need to restructure this code along more conventional lines, with explicit Connector and Statement objects as local variables so you can close them in reverse order of acquisition.
You should be using PreparedStatements instead of building arguments into SQL strings. If you throw an exception you are also leaking the result set.
For example:
public Querellante buscarQuerellante(String cedula) throws java.sql.SQLException,Exception{
String sql = "SELECT DireccionQ,NombreQ,ApellidosQ,TelefonoQ,CedulaQ "+
"FROM tquerellante "+
"WHERE CedulaQ=?";
try (Connnector conn = ...; // TODO
PreparedStatement ps = conn.prepareStatement(sql);
)
{
ps.setObject(1, cedula);
try (ResultSet rs = ps.execute())
{
if (rs.next()){
return new Querellante(
rs.getString("DireccionQ"),
rs.getString("NombreQ"),
rs.getString("ApellidosQ"),
rs.getString("TelefonoQ"),
rs.getString("CedulaQ"));
} else {
throw new Exception ("Persona no encontrada intentelo de nuevo.");
}
}
}
}
Note that try-with-resources always closes everything allocated, and in the reverse order of acquisition.
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();
I successfully can delete an integer but when I tried to make it a STRING it says
"unknown column itemtodelete in where clause but my ITEMTODELETE is a STRING declared in the database not an integer how much It doesn't delete a STRING?
below is my code:
private void DeleteButtonActionPerformed(java.awt.event.ActionEvent evt) {
int del = (prompt):
if (del == JOptionPane.YES_OPTION){
DelCurRec();
}
}
public void DelCurRec() {
String id = field.getText();
String SQL = "DELETE FROM inventory WHERE ItemCode = "+id+" ";
try {
Class.forName(connectio);
} catch (Exception e) {
JOptionPane.showMessageDialog(null,""+e.getMessage(),"JDBC Driver Error",JOptionPane.WARNING_MESSAGE);
}
Statement stmt = null;
Connection con = null;
//Creates connection to database
try {
con = DriverManager.getConnection("Connection");
stmt = con.createStatement();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,""+e.getMessage(),"Connection Error",JOptionPane.WARNING_MESSAGE);
}
//Execute the SQL statment for deleting records
try {
stmt.executeUpdate(SQL);
//This closes the connection to the database
con.close();
//This closes the dialog
JOptionPane.showMessageDialog(null,"Deleted Succesfully","Delete Successful",JOptionPane.WARNING_MESSAGE);
} catch (Exception e) {
JOptionPane.showMessageDialog(null,""+e.getMessage(),"Communication Error",JOptionPane.WARNING_MESSAGE);
}
}
Do NOT use a Statement use a PreparedStatement instead, otherwise your application will be vulnerable to SQL injections. E.g. someone enters a string like: "'; drop table inventory; --"
The corresponding prepared statment would look something like:
String SQL = "DELETE FROM inventory WHERE ItemCode = ? ";
PreparedStatement pstmt = null;
// get a connection and then in your try catch for executing your delete...
pstmt = con.prepareStatement(SQL);
pstmt.setString(1, id);
pstmt.executeUpdate();
try changing the line:
String SQL = "DELETE FROM inventory WHERE ItemCode = "+id+" ";
to
String SQL = "DELETE FROM inventory WHERE ItemCode = '"+id+"' ";
I think you need to pass Integer.parseInt(id) and not id...assuming your id is int
This worked for me:
Statement stmt=con.createStatement();
stmt.executeUpdate("DELETE FROM student WHERE reg_number='R18854';");