Here is a table in oracle db:
ID varchar2() primary key,
STATUS varchar2(),
....
I need to select rows with status 'DELAYED' and in same time set status 'PROGRESS'.
Any way to do it using JDBC?
Here is a table in oracle db:
ID varchar2() primary key,
STATUS varchar2(),
....
I need to select rows with status 'DELAYED' and in same time set status 'PROGRESS'.
Any way to do it using JDBC?
You can use the PL/SQL UPDATE .. RETURNING syntax. I think the BULK COLLECT INTO semantics still can't be used with jdbc directly, so you have to use an anonymous PL/SQL block and some tricks, instead:
-- An auxiliary package is needed to declare the type.
create or replace package p as
type t is table of my_table%rowtype;
end p;
/
declare
r p.t;
c sys_refcursor;
begin
update my_table
set status = 'PROGRESS'
where status = 'DELAYED'
returning id, status, ...
bulk collect into r;
-- The package is needed for this syntax, which cannot yet work on types
-- declared in anonymous blocks:
open c for select * from table(r);
dbms_sql.return_result(c);
end;
/
And then fetch the result. Unfortunately, that's a bit painful as can be seen in this blog post: https://blog.jooq.org/how-i-incorrectly-fetched-jdbc-resultsets-again/
(in particular, depending on the ojdbc version, there's a bug when fetching DBMS_SQL.RETURN_RESULT results)
// Alternatively, use a prepared statement if needed
try (Statement s = con.createStatement()) {
fetchLoop:
for (int i = 0, updateCount = 0; i < 256; i++) {
boolean result = (i == 0)
? s.execute(
"""
declare
r p.t;
c sys_refcursor;
begin
...
end;
""")
: s.getMoreResults();
if (result)
try (ResultSet rs = s.getResultSet()) {
// Consume result set
}
else if ((updateCount = s.getUpdateCount()) != -1)
System.out.println("Update Count: " + updateCount);
else
break fetchLoop;
}
}
You can also fetch the SYS_REFCURSOR value as an OUT parameter of a CallableStatement
If you cannot create a package, then you could serialise individual columns using DBMS_SQL.NUMBER_TABLE etc, but that's even more involved. It would look roughly like this:
declare
o0 dbms_sql.number_table;
o1 dbms_sql.varchar2_table;
-- repeat for all columns
c0 sys_refcursor;
c1 sys_refcursor;
-- repeat for all columns
begin
update my_table
set status = 'PROGRESS'
where status = 'DELAYED'
returning id, status, ...
bulk collect into o0, o1;
-- Optional rowcount if you need that, as an OUT parameter
? := sql%rowcount;
open c0 for select * from table(o0);
open c1 for select * from table(o1);
-- These can also be fetched as OUT parameters if you want
? := c0;
? := c1;
end;
This probably causes more network traffic and requires re-assembling multiple per-column result sets into a single one, so if you can, I recommend the package approach.
This is what jOOQ is doing behind the scenes when you run an UPDATE .. RETURNING statement.
As you can not do that in JDBC directly, You could use following code snippet to do so in 2 steps, I hope it help you:
Here we should use jdbc:oracle as the driver, and update ... set ... where syntax.
First you have to call updateTable() to change all DELAYED rows to PROGRESS and then call getAllDelayedObjects() to get all DELAYED rows as a List.
(Use your own Entity Type which you want to keep database results (in getAllDelayedObjects()) instead of YourEntityClass OR you could just print resultSet in console)
public class DataAccess {
private Connection connection;
private Statement statement;
public boolean updateTable() throws SQLException {
openConnection();
try (PreparedStatement statement=
connection.prepareStatement("update yourTableName set STATUS=? where STATUS=?")
) {
statement.setString(1, "DELAYED");
statement.setString(2, "PROGRESS");
if (statement.executeUpdate()>0) {
closeConnection();
return true;
}
else {
closeConnection();
return false;
}
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}
public List<YourEntityClass> getAllDelayedObjects() throws SQLException {
openConnection();
try (
PreparedStatement statement = connection.prepareStatement("select * from users where STATUS=?")
) {
statement.setString(2, "PROGRESS");
ResultSet resultSet = statement.executeQuery();
List<YourEntityClass> entityObjects = new ArrayList<>();
while (resultSet.next()) {
YourDaType object = new YourDaType();
entityObject.setId(resultSet.getInt("ID"));
entityObject.setStatus(resultSet.getString("STATUS"));
// and whatever more properties you have in the table
entityObjects.add(object);
}
closeConnection();
return entityObjects;
}
catch (Exception e) {
closeConnection();
e.printStackTrace();
return null;
}
}
public void openConnection() throws SQLException {
String username = "yourUserNameForDB";
String pass = "yourPasswordForDB";
connection = DriverManager.getConnection("jdbc:oracle://yourDBdomain:yourDBport/yourDataBaseName", username, pass);
}
public void closeConnection() throws SQLException {
this.connection.close();
}
}