Is there a way to retrieve the auto generated key from a DB query when using a java query with prepared statements.
For example, I know AutoGeneratedKeys can work as follows.
stmt = conn.createStatement();
stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
if(returnLastInsertId) {
ResultSet rs = stmt.getGeneratedKeys();
rs.next();
auto_id = rs.getInt(1);
}
However. What if I want to do an insert with a prepared Statement.
String sql = "INSERT INTO table (column1, column2) values(?, ?)";
stmt = conn.prepareStatement(sql);
//this is an error
stmt.executeUpdate(Statement.RETURN_GENERATED_KEYS);
if(returnLastInsertId) {
//this is an error since the above is an error
ResultSet rs = stmt.getGeneratedKeys();
rs.next();
auto_id = rs.getInt(1);
}
Is there a way to do this that I don't know about. It seems from the javadoc that PreparedStatements can't return the Auto Generated ID.
Yes. See here. Section 7.1.9. Change your code to:
String sql = "INSERT INTO table (column1, column2) values(?, ?)";
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
stmt.executeUpdate();
if(returnLastInsertId) {
ResultSet rs = stmt.getGeneratedKeys();
rs.next();
auto_id = rs.getInt(1);
}
There's a couple of ways, and it seems different jdbc drivers handles things a bit different, or not at all in some cases(some will only give you autogenerated primary keys, not other columns) but the basic forms are
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
Or use this form:
String autogenColumns[] = {"column1","column2"};
stmt = conn.prepareStatement(sql, autogenColumns)
Yes, There is a way. I just found this hiding in the java doc.
They way is to pass the AutoGeneratedKeys id as follows
String sql = "INSERT INTO table (column1, column2) values(?, ?)";
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
I'm one of those that surfed through a few threads looking for solution of this issue ... and finally get it to work. FOR THOSE USING jdbc:oracle:thin: with ojdbc6.jar PLEASE TAKE NOTE:
You can use either methods:
(Method 1)
Try{
String yourSQL="insert into Table1(Id,Col2,Col3) values(SEQ.nextval,?,?)";
myPrepStatement = <Connection>.prepareStatement(yourSQL, Statement.RETURN_GENERATED_KEYS);
myPrepStatement.setInt(1, 123);
myPrepStatement.setInt(2, 123);
myPrepStatement.executeUpdate();
ResultSet rs = getGeneratedKeys;
if(rs.next()) {
java.sql.RowId rid=rs.getRowId(1);
//what you get is only a RowId ref, try make use of it anyway U could think of
System.out.println(rid);
}
} catch (SQLException e) {
//
}
(Method 2)
Try{
String yourSQL="insert into Table1(Id,Col2,Col3) values(SEQ.nextval,?,?)";
//IMPORTANT: here's where other threads don tell U, you need to list ALL cols
//mentioned in your query in the array
myPrepStatement = <Connection>.prepareStatement(yourSQL, new String[]{"Id","Col2","Col3"});
myPrepStatement.setInt(1, 123);
myPrepStatement.setInt(2, 123);
myPrepStatement.executeUpdate();
ResultSet rs = getGeneratedKeys;
if(rs.next()) {
//In this exp, the autoKey val is in 1st col
int id=rs.getLong(1);
//now this's a real value of col Id
System.out.println(id);
}
} catch (SQLException e) {
//
}
Basically, try not used Method1 if you just want the value of SEQ.Nextval, b'cse it just return the RowID ref that you may cracked your head finding way to make use of it, which also don fit all data type you tried casting it to! This may works fine (return actual val) in MySQL, DB2 but not in Oracle.
AND, turn off your SQL Developer, Toad or any client which use the same login session to do INSERT when you're debugging. It MAY not affect you every time (debugging call) ... until you find your apps freeze without exception for some time. Yes ... halt without exception!
Connection connection=null;
int generatedkey=0;
PreparedStatement pstmt=connection.prepareStatement("Your insert query");
ResultSet rs=pstmt.getGeneratedKeys();
if (rs.next()) {
generatedkey=rs.getInt(1);
System.out.println("Auto Generated Primary Key " + generatedkey);
}
Related
I don't have much experience in using JAVA with SQL Server or any other database, so I'm having some trouble at the moment.
I have the following code:
public void insertProjeto(Planejado p){
String verifica="SELECT cd_projeto FROM PROJETO WHERE cd_projeto = ?";
String sqlInsert="INSERT INTO PROJETO (cd_projeto, ds_projeto) VALUES (?, ?)";
String projeto = p.getProjeto();
String nomeProjeto = p.getNomeProj();
PreparedStatement stmt;
try {
stmt = getDBConnection().prepareStatement(verifica);
stmt.setString(1, projeto);
ResultSet rs = stmt.executeQuery();
if (rs.equals("") || rs.equals(null)) {
System.out.println("------------------");
stmt = getDBConnection().prepareStatement(sqlInsert);
stmt.setString(1, projeto);
stmt.setString(2, nomeProjeto);
stmt.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
My goal is insert a register without duplicates, but for some reason my "if" isn't working.
Can anybody help me find out why?
Thanks in advance
When obtaining a ResultSet, you must call its next() method to have it progress to the first row of data if any. In case there is no data in the ResultSet object, rs.next() will return false.
There are better ways to prevent duplicates on SQL tables depends on what SQL server you're using (MS SQL, MySQL etc.)
If you're using MySQL, you can make cd_projeto a primary key and call REPLACE INTO instead of INSERT INTO, it will result in updating the record for cases it exist and inserting a new one when it doesn't.
Solved.
try {
stmt = getDBConnection().prepareStatement(verifica);
stmt.setString(1, projeto);
ResultSet rs = stmt.executeQuery();
while(!rs.next()) {
System.out.println("------------------");
stmt = getDBConnection().prepareStatement(sqlInsert);
stmt.setString(1, projeto);
stmt.setString(2, nomeProjeto);
stmt.executeUpdate();
break;
}
} catch (SQLException e) {
e.printStackTrace();
}
Don't know if it's the best way to do it, but works.
Thank you for the tips
i have the below code, where I'm inserting records to a table. When I try to get resultset, it returns null. How to get the latest added row into a resultset?
String sql1 = "INSERT INTO [xxxx].[dbo].[xxxxxx](WORKFLOW_SEQ_NBR," +
" WORKFLOW_LOG_TYPE_CODE, WORKFLOW_STATUS_CODE, DISP_CODE, DISP_USER, DISP_COMMENT, DISP_TITLE, DISP_TS)" +
"VALUES(?,?,?,?,?,?,?,?)";
PreparedStatement pst = connect.prepareStatement(sql1);
pst.setString(1, ...);
pst.setString(2, ...);
...
...
...
pst.executeUpdate();
ResultSet rstest = pst.executeQuery();
// ResultSet rstest = pst.getResultSet();
EDIT: Resolved
added following method to go to the last added row
st.execute("Select * from [xxxx].[dbo].[xxxxxxxxx]");
ResultSet rstest = st.getResultSet();
rstest.afterLast();
GETLASTINSERTED:
while(rstest.previous()){
System.out.println(rstest.getObject(1));
break GETLASTINSERTED;//to read only the last row
}
When using a SQL statement such as INSERT, UPDATE or DELETE with a PreparedStatement, you must use executeUpdate, which will return the number of affeted rows. In this case there is simply no ResultSet produced by the sql operation and thus calling executeQuery will throw a SQLException.
If you actually need a ResultSet you must make another statement with a SELECT SQL operation.
See the javadoc for PreparedStatement#executeQuery and PreparedStatement#executeUpdate
Seems like this is an older question, but i'm looking for a similar solution, so maybe people will still need this.
If you're doing an insert statement, you can use the :
Connection.PreparedStatement(String, String[]) constructor, and assign those to a ResultSet with ps.getGeneratedKeys().
It would look something like this:
public void sqlQuery() {
PreparedStatement ps = null;
ResultSet rs = null;
Connection conn; //Assume this is a properly defined Connection
String sql = "insert whatever into whatever";
ps = conn.prepareStatement(sql, new String[]{"example"});
//do anything else you need to do with the preparedStatement
ps.execute;
rs = ps.getGeneratedKeys();
while(rs.next()){
//do whatever is needed with the ResultSet
}
ps.close();
rs.close();
}
Connection#prepareStatement() - Creates a PreparedStatement object for sending parameterized SQL statements to the database.
which means connect.prepareStatement(sql1); created the PreparedStatement object using your insert query.
and when you did pst.executeUpdate(); it will return the row count for SQL Data Manipulation Language (DML) statements or 0 for SQL statements that return nothing
Now if you again want to fetch the data inserted you need to create a new PreparedStatement object with Select query.
PreparedStatement pstmt = connect.prepareStatement("SELECT * FROM tableName");
then this shall give you the ResultSet object that contains the data produced by the query
ResultSet rstest = pstmt.executeQuery();
I am trying to write a method to have an UPSERT functionality with a prepared statement in java. The code looks as follows;
public boolean addUserDeviceToken(String userid, String password, String deviceToken, Connection connection) {
String addDeviceToken = "INSERT INTO swiped.Users (userid, password, deviceToken) VALUES( ?, ?, ?) ON DUPLICATE KEY UPDATE devicetoken = ?";
boolean result = false;
ResultSet rs = null;
PreparedStatement st = null;
try {
st = connection.prepareStatement(addDeviceToken);
st.setString(1, userid);
st.setString(2, password);
st.setString(3, deviceToken);
st.setString(4, deviceToken);
What I am unsure of is whether i use st.executeQuery(); or st.executeUpdate(); as surely it depends on the condition of the duplicate key?
What is the correct approach
thanks
You don't want to get a resultSet, there's no result apart the number of insertions or updates, simply use executeUpdate.
Extract from the javadoc :
Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement
I am using following method for calculating payroll by using jdbc but "ORA-01008: not all variables bound" error is not removing.
Any idea please?
I am using following code
public double getPayroll(){
ResultSet rs = null;
ResultSet rs1 = null;
ResultSet rs2 = null;
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getDBConnection();
double dailyPay=0,basicPay=0,payroll2=0;
int houseRent=0,convAllow=0,noOfPresents=0,empId=0;
String q = "select e_id from employee";
pstmt = conn.prepareStatement(q);
rs = pstmt.executeQuery();
while (rs.next()) {
empId=rs.getInt(1);
String q1 = "select count(att_status) from attendance where att_status='p'";
pstmt = conn.prepareStatement(q1);
rs1 = pstmt.executeQuery(q1);
while(rs1.next()){
noOfPresents=rs1.getInt(1);
String q2 = "select e_salary,e_house_rent,e_conv_allow from employee where e_id=?";
pstmt = conn.prepareStatement(q2);
pstmt.setInt(1,empId);
rs2 = pstmt.executeQuery(q2);
while(rs2.next()){
dailyPay=rs2.getInt(1)/22;
houseRent=rs2.getInt(2);
convAllow=rs2.getInt(3);
basicPay=dailyPay*noOfPresents;
payroll2+=basicPay+houseRent+convAllow;
}
}
}
return payroll2;
}catch (Exception e) {
e.printStackTrace();
return 0.0;
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Your problem is here:
rs2 = pstmt.executeQuery(q2);
You're telling the PreparedStatement to execute the SQL q2, rather than executing the SQL previously prepared. This should just be:
rs2 = pstmt.executeQuery();
This is a fairly common mistake, caused mainly by the bad class design of java.sql.Statement and its subtypes.
As #RMT points out, you make the same mistake here:
rs1 = pstmt.executeQuery(q1);
This doesn't matter so much, since there are no placeholders in q1, so the SQL executes as-is. It's still wrong, though.
Lastly, you should consider calling close() on the first PreparedStatement, before re-assigning the pstmt variable to another one. You risk a leak if you don't do that.
pstmt = conn.prepareStatement(q2);
pstmt.setInt(1,empId);
rs2 = pstmt.executeQuery(q2);
You have already created the prepared statement with the query q2 and bound the variable empId to it. if you now invoke pstmt.executeQuery(q2), the variable binding is lost. The JDBC driver probably parses the unbound sql q2 when you execute pstmt.executeQuery(q2).
One reason might be that you cannot re-use the instance of pstmt like that. You have to use a separate PreparedStatement instance in each level of the loop.
Are you aware that this can be done with just a single statement as well?
Edit:
Assuming there is a relation between employee and attendance, something like this would return the sum in a single request:
select sum( (e_salary / 22) * att_count + e_house_rent + e_conv_allow )
from (
select emp.e_salary
emp.e_house_rent,
emp.e_conv_allow,
(select count(att.att_status) from attendance att where att.e_id = mp.e_id) s att_count
from employee emp
) t
If indeed attendance is not linked to employee, just leave out the where clause in the nested select.
UPDATE TESTCP SET CP_KEY2 =?, CP_DESC =?, CP_MAKER =?, CP_MAKER_DT =SYSDATE, CP_STATUS ='M' WHERE CP_LANGUAGE = ? AND CP_ENG_CODE = ? AND CP_KEY1 =? AND CP_LANGUAGE =?
In the above query we have 7 in parameter but if in your java code PreparedStatement you have set only 6 parameter values .
That time also this error will occur.
I'm doing a simple preparedstatement query execution and its throwing me this error:
java.sql.SQLException: Use of the executeQuery(string) method is not supported on this type of statement at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.notSupported(JtdsPreparedStatement.java:197) at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java:822) at testconn.itemcheck(testconn.java:58)
Any ideas what i'm doing incorrectly? thanks in advance
here is the code:
private static int itemcheck (String itemid ) {
String query;
int count = 0;
try {
Class.forName("net.sourceforge.jtds.jdbc.Driver");
con = java.sql.DriverManager.getConnection(getConnectionUrl2());
con.setAutoCommit(false);
query = "select count(*) as itemcount from timitem where itemid like ?";
//PreparedStatement pstmt = con.prepareStatement(query);
//pstmt.executeUpdate();
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1,itemid);
java.sql.ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
count = rs.getInt(1);
System.out.println(count);
} //end while
}catch(Exception e){ e.printStackTrace(); }
return (count);
} //end itemcheck
A couple of things are worth checking:
Use a different alias. Using COUNT as an alias would be asking for trouble.
The query object need not be passed twice, once during preparation of the statement and later during execution. Using it in con.prepareStatement(query); i.e. statement preparation, is enough.
ADDENDUM
It's doubtful that jTDS supports usage of the String arg method for PreparedStatement. The rationale is that PreparedStatement.executeQuery() appears to be implemented, whereas Statement.executeQuery(String) appears to have been overriden in PreparedStatement.executeQuery() to throw the stated exception.
So...
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1,itemid);
java.sql.ResultSet rs = pstmt.executeQuery(query);
Unlike Statement, with PreparedStatement you pass the query sql when you create it (via the Connection object). You're doing it, but then you're also passing it again, when you call executeQuery(query).
Use the no-arg overload of executeQuery() defined for PreparedStatement.
So...
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1,itemid);
java.sql.ResultSet rs = pstmt.executeQuery();