我有一个PL / SQL存储的函数,该函数返回一个整数表:
CREATE TYPE INT_TABLE IS TABLE OF INTEGER;
CREATE FUNCTION f (someParam IN INTEGER) RETURN INT_TABLE IS ...
我希望使用JDBC来检索此函数的结果,以便可以以某种方式遍历整数,无论是ResultSet
,int[]
还是其他。
函数f
对数据库进行了修改,因此无法在诸如SELECT f(42) FROM DUAL;
的查询中调用它。该返回值的存在是为了将其修改的行的主键通知给调用者。我大概必须使用CallableStatement
,但无法确切知道如何使用。从here获得灵感,我尝试过:
CallableStatement cs = conn.prepareCall("{? = call f(42)}");
cs.registerOutParameter(1, Types.ARRAY);
cs.execute();
ResultSet rs = cs.getArray(1).getResultSet();
但是,这导致java.sql.SQLException: Invalid argument(s) in call
行上出现registerOutParameter
。我无法确定此错误的实际含义,因为文档对于可能引发的异常非常笼统。
我花了数小时的时间进行谷歌搜索,但对如何进行操作却感到茫然。是否可以将表类型提取到Java中?如果没有,还有其他方法可以从可以提取到Java中的PL / SQL函数返回多个整数吗?
我想出自己的问题后便回答了。
我非常接近解决方案;我只是想念在registerOutParameter
调用中指定类型名称。因此,最终的解决方案如下所示:
cs = conn.prepareCall("{? = call f(42)}");
cs.registerOutParameter(1, Types.ARRAY, "INT_TABLE");
cs.execute();
ResultSet rs = cs.getArray(1).getResultSet();
这是本机JDBC,不需要任何Oracle扩展。
令我震惊的另一件事是此ResultSet
的结构。它包含两列;第一个是索引,第二个是值(documentation link)。因此,如果要提取数组的元素,则需要为每行调用rs.getInt(2)
,而不是rs.getInt(1)
。
如果不是将结果作为纯数组而不是ResultSet,则对应的类型是java.math.BigDecimal
,所以它是
...
cs.execute();
BigDecimal[] array = (BigDecimal[])(cs.getArray(1).getArray());
是的,从oracle可以返回整数或其他类型的表。我认为,您需要定义oracle类型
订购时:1.创建类型和功能
CREATE TYPE array_int IS TABLE OF INTEGER;
CREATE OR REPLACE FUNCTION get_array (v_id IN INTEGER)
RETURN array_int
IS
res array_int := array_int(1,2,3,4);
begin
return res;
end;
和Java
ArrayList r_list = new ArrayList();
ArrayDescriptor arrayInt = ArrayDescriptor.createDescriptor("ARRAY_INT", con); //to oracle type
ARRAY iarray = new ARRAY(arrayInt, con, r_list.toArray());
OracleCallableStatement cst = (OracleCallableStatement) con.prepareCall(
"{call ?:= get_array(?)");
cst.registerOutParameter(1, OracleTypes.ARRAY, "ARRAY_INT");
cst.setInt(2, 1);
cst.execute();
iarray = cst.getARRAY(1);
cst.close();
Object[] pObjects = (Object[]) iarray.getArray();
for (int i = 0; i < pObjects.length; i++) {
System.out.print(pObjects[i]);
}