I'm new to using Oracle so I'm going off what has already been previously answered in this SO question. I just can't seem to get it to work. Here's the statement that I'm using:
declare
lastId number;
begin
INSERT INTO "DB_OWNER"."FOO"
(ID, DEPARTMENT, BUSINESS)
VALUES (FOO_ID_SEQ.NEXTVAL, 'Database Management', 'Oracle')
RETURNING ID INTO lastId;
end;
When I call executeQuery the PreparedStatement that I have made, it inserts everything into the database just fine. However, I cannot seem to figure out how to retrieve the ID. The returned ResultSet object will not work for me. Calling
if(resultSet.next()) ...
yields a nasty SQLException that reads:
Cannot perform fetch on a PLSQL statement: next
How do I get that lastId? Obviously I'm doing it wrong.
make it a function that returns it to you (instead of a procedure). Or, have a procedure with an OUT parameter.
Not sure if this will work, since I've purged all of my computers of anything Oracle, but...
Change your declare to:
declare
lastId OUT number;
Switch your statement from a PreparedStatement to a CallableStatement by using prepareCall() on your connection. Then register the output parameter before your call, and read it after the update:
cstmt.registerOutParameter(1, java.sql.Types.NUMERIC);
cstmt.executeUpdate();
int x = cstmt.getInt(1);
I tried with Oracle driver v11.2.0.3.0 (since there are some bugs in 10.x and 11.1.x, see other blog). Following code works fine:
final String sql = "insert into TABLE(SOME_COL, OTHER_COL) values (?, ?)";
PreparedStatement ps = con.prepareStatement(sql, new String[] {"ID"});
ps.setLong(1, 264);
ps.setLong(2, 1);
int executeUpdate = ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next() ) {
// The generated id
long id = rs.getLong(1);
System.out.println("executeUpdate: " + executeUpdate + ", id: " + id);
}
When you prepare the statement set the second parameter to RETURN_GENERATED_KEYS. Then you should be able to get a ResultSet off the statement object.
You can use Statement.getGeneratedKeys() to do this. You just need to make sure to tell JDBC what columns you want back using one of the method overloads for that, such as the Connection.prepareStatement overload here:
Connection conn = ...
PreparedStatement pS = conn.prepareStatement(sql, new String[]{"id"});
pS.executeUpdate();
ResultSet rS = pS.getGeneratedKeys();
if (rS.next()) {
long id = rS.getLong("id");
...
}
You don't need to do the RETURNING x INTO stuff with this, just use the basic SQL statement you want.
Are you doing that in a stored procedure ? According to this Oracle document, it won't work with the server-side driver.
The Oracle server-side internal driver does not support
the retrieval of auto-generated keys feature.
Related
I have a section in my application which require to update two tables at the same time (WORKTR and BRTR).
However, the program only works on the first table update query while the second query did not work, resulting only a table been updated. There are no error prompt at the Log error.
Here is my jdbc code to update both table:
String query=("UPDATE WORKTR SET status = ? WHERE Pf_no = ? AND status = ? AND Scan_by= ? AND Start_date= ?");
PreparedStatement ps = con.prepareStatement(query);
// set the preparedstatement parameters
ps.setString(1,a_status);
ps.setString(2,OperatorPF);
ps.setString(3,b_status);
ps.setString(4,PIC);
ps.setString(5,dates);
// call executeUpdate to execute our sql update statement
ps.executeUpdate();
if (ps.executeUpdate()==1) {
String queryBRTR= ("Update BRTR set end_break = ?, status= ? where and PF_No= ? and work_date= ?");
PreparedStatement br = con.prepareStatement(queryBRTR);
// set the preparedstatement parameters
br.setString(1,currentTime);
br.setString(2,a_status);
// br.setString(3,b_status);
br.setString(3,OperatorPF);
br.setString(4,dates);
// call executeUpdate to execute our sql update statement
br.executeUpdate();
if( br.executeUpdate()==1){
z="You may resume your work now";
}
else{
ps.close();
br.close();
}
Please highlight if there is any mistake or suggest another way that would work to update both table.
Change to
int rowsChanged = ps.executeUpdate();
if (rowsChanged >= 1) {
You were calling executeUpdate twice.
Should not re-execute the PreparedStatement
Status has changed so even if you could re-use PreparedStatement , the update would probably fail
I am using temporary tables inside my code in order to [some long sequnce of reasons here] in SQL Server, Java. I was executing my sql queries with using Stament object in java. However, recently I decided to use PreparedStatement in order to avoid injection thing.
My problem is when create a temporary table with using PreparedStatement, I can not reach it with the same prepared statement again. Here is a simple illustration:
sql = "select * into #someTable from (select someColumns from someOtherTable where smth = ? and smth2 = ?)"
PreparedStatement preparedStatement = conn.prepareStatement(sql);
for(int i=0; i<parameters.size(); i++){
preparedStatement.setString(i+1, parameters.get(i).toString());
}
this.rs = preparedStatement.executeQuery();
Until here, it is ok. After getting ResultSet and doing something with it, or without getting a resultSet just for preparedStatement.execute() does not makes difference, I can not reach the #someTable object again.
sql = "select count(*) from #someTable"
preparedStatement = conn.prepareStatement(sql);
this.rs = preparedStatement.executeQuery();
Here this.rs = preparedStatement.executeQuery(); part gives 'Invalid object name #someTable'. I am doing all of the things above with using one Connection object only and without closing or reopening it. I need to use that temp table again. Is there any way to create temp table with PreparedStatement object in java and reuse this temp table again and again? Regards,
Rather late to the party, but facing the same problem and finding the above answer wrong:
Read this article about the problem: https://learn.microsoft.com/en-us/sql/connect/jdbc/using-usefmtonly?view=sql-server-2017
I found that using a PreparedStatement to create the temp table wouldn't work, but if I changed to use a Statement to create the temp table it would work (even without the useFmtOnly).
So start with this (from the MS article) and build on it:
final String sql = "INSERT INTO #Bar VALUES (?)";
try (Connection c = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
try (Statement s = c.createStatement()) {
s.execute("CREATE TABLE #Bar(c1 int)");
}
try (PreparedStatement p1 = c.prepareStatement(sql); PreparedStatement p2 = c.prepareStatement(sql)) {
((SQLServerPreparedStatement) p1).setUseFmtOnly(true);
ParameterMetaData pmd1 = p1.getParameterMetaData();
System.out.println(pmd1.getParameterTypeName(1)); // prints int
ParameterMetaData pmd2 = p2.getParameterMetaData(); // throws exception, Invalid object name '#Bar'
}
}
The temp table you create in the first statement exists for the scope\lifetime of that request. As soon as you call another query, you're in a different scope so it is no longer present as it would have been cleaned up.
Solutions are either make 2 requests in the same call (not great) or create a global temp table that can be accessed by the second query (still not great).
The better solution is to create a stored procedure that does everything you need, with the temp table creation, querying and tidy up encapsulated in the procedure.
PS I can't see any surrounding code, but beware of SQL Injection when building queries in code like this.
Related info:
Scope of temporary tables in SQL Server
How can I update my SQL Table column with the value that is stored in a local variable.
In my program I have taken value from the HTML page using the following statement:
String idd=request.getParameter("id");
String report=request.getParameter("rprt");
So now I have to update the value of report in my database table named "ptest" and I am using the following query:
Class.forName("com.mysql.jdbc.Driver");
java.sql.Connection con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/tcs","root","root");
Statement st= con.createStatement();
ResultSet rs;
int i=st.executeUpdate("update ptest set result = #reprt where patient_id=
#idd");
out.println("Successfully Entered");
But the value is not being stored in the database instead NULL is being stored.
I have already seen this question and got no help.
Question
Please ignore my mistakes if any in this question as I am new to MYSQL.
You can use prepared statements in java.
setString or setInt can set different data types into your prepared statements.
The parameter 1, 2 are basically the positions of the question mark. setString(1,report) means that it would set the string report in the 1st question mark in your query.
Hope this code helps you in achieving what you want.
String query = "update ptest set result = ? where patient_id = ?";
PreparedStatement preparedStatement = con.prepareStatement(query);
preparedStatement.setString(1, report);
preparedStatement.setString(2, idd);
preparedStatement.executeUpdate();
In JDBC, you use ? as placeholders for where you want to inject values into a statement.
So you should do something like this ...
Class.forName("com.mysql.jdbc.Driver");
java.sql.Connection con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/tcs","root","root");
PreparedStatement st= con.prepareCall("update ptest set result = ? where patient_id=
?");
///now set the params in order
st.setString(1, report);
st.setString(2, idd);
//then execute
st.executeUpdate();
Doing a string concat with the values is dangerous due to sql injection possibilities, so I typically make statement text static and final, and also if your value has a ' in it that could blow up your sql syntax etc. Also, notice the use of executeUpdate rather than query.
Hope this helps
I have an assignment where I need to update records using a PreparedStatement. Once the record have been updated as we know update query return count, i.e., number of row affected.
However, instead of the count I want the rows that were affected by update query in response, or at least a list of id values for the rows that were affected.
This my update query.
UPDATE User_Information uInfo SET address = uInfo.contact_number || uInfo.address where uInfo.user_id between ? AND ?;
Normally it will return count of row affected but in my case query should return the ids of row or all the row affected.
I have used the returning function of PostgreSQL it is working but is not useful for me in that case.
i have used returning function of PostgreSQL but is not useful for me
It should be. Perhaps you were just using it wrong. This code works for me:
sql = "UPDATE table1 SET customer = customer || 'X' WHERE customer LIKE 'ba%' RETURNING id";
try (PreparedStatement s = conn.prepareStatement(sql)) {
s.execute(); // perform the UPDATE
try (ResultSet rs = s.getResultSet()) {
// loop through rows from the RETURNING clause
while (rs.next()) {
System.out.println(rs.getInt("id")); // print the "id" value of the updated row
}
}
}
The documentation indicates that we can also use RETURNING * if we want the ResultSet to include the entire updated row.
Update:
As #CraigRinger suggests in his comment, the PostgreSQL JDBC driver does actually support .getGeneratedKeys() for UPDATE statements too, so this code worked for me as well:
sql = "UPDATE table1 SET customer = customer || 'X' WHERE customer LIKE 'ba%'";
try (PreparedStatement s = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
s.execute(); // perform the UPDATE
try (ResultSet rs = s.getGeneratedKeys()) {
while (rs.next()) {
System.out.println(rs.getInt(1)); // print the "id" value of the updated row
}
}
}
Thanks, Craig!
You might be able to use JDBC's support for getting generated keys. See the Connection.prepareStatement(String sql, int[] columnIndexes) API method, then use Statement.getGeneratedKeys() to access the results.
The spec says "the driver will ignore the array if the SQL statement is not an INSERT statement" but I think PostgreSQL's JDBC driver will actually honour your request with other statement types too.
e.g.
PreparedStatement s = conn.prepareStatement(sql, new String[] {'id'})
s.executeUpdate();
ResultSet rs = s.getGeneratedKeys();
Otherwise, use RETURNING, as Gord Thompson describes.
There are two way of doing it
1. by passing an array of column name or index of column prepareStatement
i.e conn.prepareStatement(sql, new String[] {'id','uname'})
and
2. by using Statement.RETURN_GENERATED_KEYS in prepareStatement.
My code is for this i.e as per my requirement i have developed my code you can have a look for better idea.
private static final String UPDATE_USER_QUERY= "UPDATE User_Information uInfo SET address = uInfo.contact_number || uInfo.address where uInfo.user_id between ? AND ?;";
//pst = connection.prepareStatement(UPDATE_USER_QUERY,columnNames);
pst = connection.prepareStatement(UPDATE_USER_QUERY,Statement.RETURN_GENERATED_KEYS);
ResultSet rst = pst.getGeneratedKeys();
List<UserInformation> userInformationList = new ArrayList<UserInformation>();
UserInformation userInformation;
while (rst.next()){
userInformation = new UserInformation();
userInformation.setUserId(rst.getLong("user_id"));
userInformation.setUserName(rst.getString("user_name"));
userInformation.setUserLName(rst.getString("user_lName"));
userInformation.setAddress(rst.getString("address"));
userInformation.setContactNumber(rst.getLong("contact_number"));
userInformationList.add(userInformation);
}
That think i need to achieve in this case.
Hope so this will help you a lot.
This is what I want to do:
PreparedStatement query2 =
conn.prepareStatement ("UPDATE report SET Name = ? WHERE Id = ?");
String blah = "Jane";
int id = 1;
query2.setString(1, blah);
query2.setInt(2, id);
query2.executeQuery();
But I'm getting this error:
The statement did not return a result set.
I am new to the whole jdbc world. Where am I going wrong here?
You should use executeUpdate.
"Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement."