我有一个表单的SQL语句:
BEGIN\n
UPDATE tab
SET stuff
WHERE stuff
RETURNING intA, intB, stringC
INTO ?,?,?
我已经注册了相应的Out参数。
这里有一些问题:我是否调用stmt.executeQuery()或stmt.execute()?此外,我知道使用普通的SELECT查询,我可以循环遍历resultSet并填充我的对象 - 多行Out参数的等价物是什么?
编辑: 也许我可以注册CURSOR类型的单个输出参数并循环遍历此结果。
EDIT2: 我可能有多个需要循环的结果集吗? 谢谢!
答案 0 :(得分:4)
要根据Luke Woodward的回答并优化我之前的答案,您可以创建Oracle类型,使用它来临时存储数据,然后返回带有更新的sys_refcursor。
创建新类型:
CREATE OR REPLACE TYPE rowid_tab AS TABLE OF varchar2(30);
创建数据库功能:
CREATE OR REPLACE
FUNCTION update_tab
RETURN sys_refcursor
IS
ref_cur sys_refcursor;
v_tab rowid_tab;
BEGIN
UPDATE tab
SET intA = intA+2
, intB = intB*2
, stringC = stringC||' more stuff.'
RETURNING ROWID
BULK COLLECT INTO v_tab;
OPEN ref_cur FOR
WITH DATA AS (SELECT * FROM TABLE(v_tab))
SELECT intA, intB, stringC
FROM tab
where rowid in (select * from data);
RETURN ref_cur;
END;
现在,在java中调用函数:
import java.math.BigDecimal;
import java.util.Arrays;
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.*;
public class StructTest {
public static void main(String[] args)
throws Exception
{
System.out.println("Start...");
ResultSet results = null;
Connection c = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:xe", "scott", "tiger");
c.setAutoCommit(false);
String sql = "begin ? := update_tab(); end;";
System.out.println("sql = "+sql);
CallableStatement stmt = c.prepareCall(sql);
/* Register the out parameter. */
System.out.println("register out param");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
// get the result set
stmt.execute();
results = (ResultSet) stmt.getObject(1);
while (results.next()){
System.out.println("intA: "+results.getString(1)+", intB: "+results.getString(2)+", stringC: "+results.getString(3));
}
c.rollback();
c.close();
}
}
根据我的测试数据,我得到了以下结果:
intA: 3, intB: 4, stringC: a more stuff.
intA: 6, intB: 10, stringC: C more stuff.
intA: 3, intB: 4, stringC: a more stuff.
答案 1 :(得分:4)
我相信你可以实现你想要的,但你需要处理PL / SQL数组而不是游标或结果集。以下是演示。
我有一个名为TEST
的表,其结构如下:
SQL> desc test; Name Null? Type ----------------------------------------- -------- ----------------- A NUMBER(38) B NUMBER(38) C NUMBER(38)
并包含以下数据:
SQL> select * from test; A B C ---------- ---------- ---------- 1 2 3 4 5 6 7 8 9
我需要为每种使用的列创建一个数组类型。在这里,我只有NUMBER
个,但如果您还有一个或多个VARCHAR2
列,则还需要为这些列创建一个类型。
SQL> create type t_integer_array as table of integer; 2 / Type created.
我们需要在数据库中设置表和任何必要的类型。完成后,我们可以编写一个简短的Java类来执行UPDATE ... RETURNING ...
,将多个值返回给Java:
import java.math.BigDecimal;
import java.util.Arrays;
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.*;
public class UpdateWithBulkReturning {
public static void main(String[] args) throws Exception {
Connection c = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:XE", "user", "password");
c.setAutoCommit(false);
/* You need BULK COLLECT in order to return multiple rows. */
String sql = "BEGIN UPDATE test SET a = a + 10 WHERE b <> 5 " +
"RETURNING a, b, c BULK COLLECT INTO ?, ?, ?; END;";
CallableStatement stmt = c.prepareCall(sql);
/* Register the out parameters. Note that the third parameter gives
* the name of the corresponding array type. */
for (int i = 1; i <= 3; ++i) {
stmt.registerOutParameter(i, Types.ARRAY, "T_INTEGER_ARRAY");
}
/* Use stmt.execute(), not stmt.executeQuery(). */
stmt.execute();
for (int i = 1; i <= 3; ++i) {
/* stmt.getArray(i) returns a java.sql.Array for the output parameter in
* position i. The getArray() method returns the data within this
* java.sql.Array object as a Java array. In this case, Oracle converts
* T_INTEGER_ARRAY into a Java BigDecimal array. */
BigDecimal[] nums = (BigDecimal[]) (stmt.getArray(i).getArray());
System.out.println(Arrays.toString(nums));
}
stmt.close();
c.rollback();
c.close();
}
}
当我运行它时,我得到以下输出:
C:\Users\Luke\stuff>java UpdateWithBulkReturning [11, 17] [2, 8] [3, 9]
显示的输出分别是A
,B
和C
列返回的值。每列只有两个值,因为我们过滤掉了B
等于5的行。
您可能希望按行分组而不是按列分组。换句话说,您可能希望输出包含[11, 2, 3]
和[17, 8, 9]
。如果这就是你想要的,我担心你自己需要做那个部分。