Arrays 获取pl/sql数组(作为out参数)
我有一个Oracle存储过程,其中一个数组作为输入参数,一个数组作为输出参数。虽然输入参数已经可以正常工作,但我总是返回一个空值数组(尽管数组的长度是我所期望的) 这只是一个测试环境,所以它只是一个简单的例子:存储过程只接受输入数组,并将值复制到输出数组和varchar2字段,因此我可以看到从输入数组复制到varchar2字段效果很好,但复制到输出数组却没有效果 我的Java代码如下所示:Arrays 获取pl/sql数组(作为out参数),arrays,oracle,stored-procedures,jdbc,Arrays,Oracle,Stored Procedures,Jdbc,我有一个Oracle存储过程,其中一个数组作为输入参数,一个数组作为输出参数。虽然输入参数已经可以正常工作,但我总是返回一个空值数组(尽管数组的长度是我所期望的) 这只是一个测试环境,所以它只是一个简单的例子:存储过程只接受输入数组,并将值复制到输出数组和varchar2字段,因此我可以看到从输入数组复制到varchar2字段效果很好,但复制到输出数组却没有效果 我的Java代码如下所示: DriverManager.registerDriver(new OracleDriver());
DriverManager.registerDriver(new OracleDriver());
Connection conn = DriverManager.getConnection(
"<ConnectionString>", "<user>", "<password>");
conn.setAutoCommit(false);
OracleConnection oracleConnection = (OracleConnection)conn;
OracleCallableStatement stmt = (OracleCallableStatement)oracleConnection.prepareCall("call MYPACKAGE.TABLE_IN_TABLE_OUT( ?, ?, ? )");
String[] inputStringArray = { "1", "2", "3", "4" };
Array inputArray = oracleConnection.createOracleArray("MYPACKAGE.CHAR_TABLE", inputStringArray);
stmt.setArray(1, inputArray);
stmt.registerOutParameter(2, Types.ARRAY, "MYPACKAGE.ERG_TABLE");
stmt.registerOutParameter(3, Types.VARCHAR);
stmt.executeUpdate();
Array resultArray = stmt.getArray(2);
String [] resultStringArray = (String[])resultArray.getArray();
String resultString = stmt.getString(3);
System.out.println(resultString);
for (String result : resultStringArray) {
System.out.println(result);
}
conn.commit();
conn.close();
存储过程的实现:
create or replace PACKAGE BODY MYPACKAGE AS
PROCEDURE TABLE_IN_TABLE_OUT(
inputArray IN CHAR_TABLE,
outputArray OUT ERG_TABLE,
resultString OUT VARCHAR2) AS
BEGIN
FOR i IN 0..inputArray.last loop
outputArray(i) := inputArray(i);
end loop;
resultString := '';
FOR i IN 0..outputArray.last loop
resultString := resultString || outputArray(i);
end loop;
END TABLE_IN_TABLE_OUT;
END MYPACKAGE;
这是输出:
VARCHAR2 result: 1234
Array result: null, null, null, null,
在互联网和本论坛上搜索了很多之后,我真的没有发现我做错了什么。不要使用PL/SQL范围(即在包中)中定义的关联数组,而是使用SQL范围中定义的集合
create or replace TYPE stringlist IS TABLE OF VARCHAR2(4000);
/
create or replace TYPE stringlist2 IS TABLE OF VARCHAR2(4000);
/
那么包是:
CREATE OR REPLACE PACKAGE mypackage
AS
PROCEDURE table_in_table_out(
inputArray IN stringlist,
outputArray OUT stringlist2,
resultString OUT VARCHAR2
);
END mypackage;
/
CREATE OR REPLACE PACKAGE BODY mypackage
AS
PROCEDURE table_in_table_out(
inputArray IN stringlist,
outputArray OUT stringlist2,
resultString OUT VARCHAR2
)
IS
i BINARY_INTEGER;
BEGIN
IF inputArray IS NULL THEN
RETURN;
END IF;
outputArray := stringlist2();
IF inputArray IS EMPTY THEN
RETURN;
END IF;
-- Handle sparse arrays
i := inputArray.FIRST;
LOOP
outputArray.EXTEND;
outputArray(outputArray.LAST) := inputArray(i);
resultString := resultString || inputArray(i);
EXIT WHEN i = inputArray.LAST;
i := inputArray.NEXT(i);
END LOOP;
END;
END mypackage;
/
在数据库中进行测试:
SET SERVEROUTPUT ON;
DECLARE
i stringList := StringList( 'A', 'C', 'F' );
e stringlist2;
s VARCHAR2(4000);
n BINARY_INTEGER;
BEGIN
i.DELETE(2);
n := i.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || i(n) );
EXIT WHEN n = i.LAST;
n := i.NEXT(n);
END LOOP;
mypackage.table_in_table_out( i, e, s );
DBMS_OUTPUT.PUT_LINE( s );
n := e.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || e(n) );
EXIT WHEN n = e.LAST;
n := e.NEXT(n);
END LOOP;
END;
/
try{
Class.forName( "oracle.jdbc.OracleDriver" );
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"username",
"password"
);
OracleConnection oCon = (OracleConnection) con;
OracleCallableStatement st = (OracleCallableStatement) con.prepareCall( "{ call mypackage.table_in_table_out( :chars, :ergs, :res )}" );
ARRAY ia = oCon.createARRAY("STRINGLIST", new String[]{ "A", "C", "F"} );
st.setARRAYAtName("chars", ia );
st.registerOutParameter( 2, java.sql.Types.ARRAY, "VARCHAR2S_TABLE" );
st.registerOutParameter( 3, java.sql.Types.VARCHAR );
System.out.println( st.execute() );
System.out.println( st.getString( 3 ) );
String[] strs = (String[]) st.getARRAY(2).getArray();
for ( String str : strs )
System.out.println(str);
st.close();
con.close();
} catch (ClassNotFoundException | SQLException ex) {
System.out.println( ex.getMessage() );
ex.printStackTrace();
}
Java:
SET SERVEROUTPUT ON;
DECLARE
i stringList := StringList( 'A', 'C', 'F' );
e stringlist2;
s VARCHAR2(4000);
n BINARY_INTEGER;
BEGIN
i.DELETE(2);
n := i.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || i(n) );
EXIT WHEN n = i.LAST;
n := i.NEXT(n);
END LOOP;
mypackage.table_in_table_out( i, e, s );
DBMS_OUTPUT.PUT_LINE( s );
n := e.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || e(n) );
EXIT WHEN n = e.LAST;
n := e.NEXT(n);
END LOOP;
END;
/
try{
Class.forName( "oracle.jdbc.OracleDriver" );
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"username",
"password"
);
OracleConnection oCon = (OracleConnection) con;
OracleCallableStatement st = (OracleCallableStatement) con.prepareCall( "{ call mypackage.table_in_table_out( :chars, :ergs, :res )}" );
ARRAY ia = oCon.createARRAY("STRINGLIST", new String[]{ "A", "C", "F"} );
st.setARRAYAtName("chars", ia );
st.registerOutParameter( 2, java.sql.Types.ARRAY, "VARCHAR2S_TABLE" );
st.registerOutParameter( 3, java.sql.Types.VARCHAR );
System.out.println( st.execute() );
System.out.println( st.getString( 3 ) );
String[] strs = (String[]) st.getARRAY(2).getArray();
for ( String str : strs )
System.out.println(str);
st.close();
con.close();
} catch (ClassNotFoundException | SQLException ex) {
System.out.println( ex.getMessage() );
ex.printStackTrace();
}
不要使用PL/SQL范围(即在包中)中定义的关联数组,而是使用SQL范围中定义的集合
create or replace TYPE stringlist IS TABLE OF VARCHAR2(4000);
/
create or replace TYPE stringlist2 IS TABLE OF VARCHAR2(4000);
/
那么包是:
CREATE OR REPLACE PACKAGE mypackage
AS
PROCEDURE table_in_table_out(
inputArray IN stringlist,
outputArray OUT stringlist2,
resultString OUT VARCHAR2
);
END mypackage;
/
CREATE OR REPLACE PACKAGE BODY mypackage
AS
PROCEDURE table_in_table_out(
inputArray IN stringlist,
outputArray OUT stringlist2,
resultString OUT VARCHAR2
)
IS
i BINARY_INTEGER;
BEGIN
IF inputArray IS NULL THEN
RETURN;
END IF;
outputArray := stringlist2();
IF inputArray IS EMPTY THEN
RETURN;
END IF;
-- Handle sparse arrays
i := inputArray.FIRST;
LOOP
outputArray.EXTEND;
outputArray(outputArray.LAST) := inputArray(i);
resultString := resultString || inputArray(i);
EXIT WHEN i = inputArray.LAST;
i := inputArray.NEXT(i);
END LOOP;
END;
END mypackage;
/
在数据库中进行测试:
SET SERVEROUTPUT ON;
DECLARE
i stringList := StringList( 'A', 'C', 'F' );
e stringlist2;
s VARCHAR2(4000);
n BINARY_INTEGER;
BEGIN
i.DELETE(2);
n := i.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || i(n) );
EXIT WHEN n = i.LAST;
n := i.NEXT(n);
END LOOP;
mypackage.table_in_table_out( i, e, s );
DBMS_OUTPUT.PUT_LINE( s );
n := e.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || e(n) );
EXIT WHEN n = e.LAST;
n := e.NEXT(n);
END LOOP;
END;
/
try{
Class.forName( "oracle.jdbc.OracleDriver" );
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"username",
"password"
);
OracleConnection oCon = (OracleConnection) con;
OracleCallableStatement st = (OracleCallableStatement) con.prepareCall( "{ call mypackage.table_in_table_out( :chars, :ergs, :res )}" );
ARRAY ia = oCon.createARRAY("STRINGLIST", new String[]{ "A", "C", "F"} );
st.setARRAYAtName("chars", ia );
st.registerOutParameter( 2, java.sql.Types.ARRAY, "VARCHAR2S_TABLE" );
st.registerOutParameter( 3, java.sql.Types.VARCHAR );
System.out.println( st.execute() );
System.out.println( st.getString( 3 ) );
String[] strs = (String[]) st.getARRAY(2).getArray();
for ( String str : strs )
System.out.println(str);
st.close();
con.close();
} catch (ClassNotFoundException | SQLException ex) {
System.out.println( ex.getMessage() );
ex.printStackTrace();
}
Java:
SET SERVEROUTPUT ON;
DECLARE
i stringList := StringList( 'A', 'C', 'F' );
e stringlist2;
s VARCHAR2(4000);
n BINARY_INTEGER;
BEGIN
i.DELETE(2);
n := i.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || i(n) );
EXIT WHEN n = i.LAST;
n := i.NEXT(n);
END LOOP;
mypackage.table_in_table_out( i, e, s );
DBMS_OUTPUT.PUT_LINE( s );
n := e.FIRST;
LOOP
DBMS_OUTPUT.PUT_LINE( n || ': ' || e(n) );
EXIT WHEN n = e.LAST;
n := e.NEXT(n);
END LOOP;
END;
/
try{
Class.forName( "oracle.jdbc.OracleDriver" );
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"username",
"password"
);
OracleConnection oCon = (OracleConnection) con;
OracleCallableStatement st = (OracleCallableStatement) con.prepareCall( "{ call mypackage.table_in_table_out( :chars, :ergs, :res )}" );
ARRAY ia = oCon.createARRAY("STRINGLIST", new String[]{ "A", "C", "F"} );
st.setARRAYAtName("chars", ia );
st.registerOutParameter( 2, java.sql.Types.ARRAY, "VARCHAR2S_TABLE" );
st.registerOutParameter( 3, java.sql.Types.VARCHAR );
System.out.println( st.execute() );
System.out.println( st.getString( 3 ) );
String[] strs = (String[]) st.getARRAY(2).getArray();
for ( String str : strs )
System.out.println(str);
st.close();
con.close();
} catch (ClassNotFoundException | SQLException ex) {
System.out.println( ex.getMessage() );
ex.printStackTrace();
}
最后(经过数小时的研究),我还找到了按表返回索引的方法,现在可以使用了。由于这是一种非常痛苦的方式,我想在这里分享我的解决方案:
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection(
"<connectionString>", "<user>", "<password>");
conn.setAutoCommit(false);
OracleConnection oracleConnection = (OracleConnection)conn;
OracleCallableStatement stmt = (OracleCallableStatement)oracleConnection.prepareCall("BEGIN MYPACKAGE.TABLE_IN_TABLE_OUT( ?, ?, ? ); END;");
String[] inputStringArray = { "1", "2", "3", "4", "5", "6"};
Array inputArray = oracleConnection.createOracleArray("MYPACKAGE.CHAR_TABLE", inputStringArray);
stmt.setArray(1, inputArray);
stmt.registerIndexTableOutParameter(2, 100, OracleTypes.VARCHAR, 100);
stmt.registerOutParameter(3, Types.VARCHAR);
stmt.execute();
String resultString = stmt.getString(3);
String[] resultArray = (String[])stmt.getPlsqlIndexTable(2);
System.out.println("VARCHAR2 result: " + resultString);
System.out.print("Array result: ");
for (String result : resultArray) {
System.out.print(result + ", ");
}
到
因为我在使用方法“registerIndexTableOutParameter”时遇到了“ORA-01484:array只能绑定到PL/SQL语句”(请参阅下一点)
stmt.registerOutParameter(2, Types.ARRAY, "MYPACKAGE.ERG_TABLE");
我现在这样做:
stmt.registerIndexTableOutParameter(2, 100, OracleTypes.VARCHAR, 100);
String[] resultArray = (String[])stmt.getPlsqlIndexTable(2);
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection(
"<connectionString>", "<user>", "<password>");
conn.setAutoCommit(false);
OracleConnection oracleConnection = (OracleConnection)conn;
OracleCallableStatement stmt = (OracleCallableStatement)oracleConnection.prepareCall("BEGIN MYPACKAGE.TABLE_IN_TABLE_OUT( ?, ?, ? ); END;");
String[] inputStringArray = { "1", "2", "3", "4", "5", "6"};
Array inputArray = oracleConnection.createOracleArray("MYPACKAGE.CHAR_TABLE", inputStringArray);
stmt.setArray(1, inputArray);
stmt.registerIndexTableOutParameter(2, 100, OracleTypes.VARCHAR, 100);
stmt.registerOutParameter(3, Types.VARCHAR);
stmt.execute();
String resultString = stmt.getString(3);
String[] resultArray = (String[])stmt.getPlsqlIndexTable(2);
System.out.println("VARCHAR2 result: " + resultString);
System.out.print("Array result: ");
for (String result : resultArray) {
System.out.print(result + ", ");
}
到
因为我在使用方法“registerIndexTableOutParameter”时遇到了“ORA-01484:array只能绑定到PL/SQL语句”(请参阅下一点)
stmt.registerOutParameter(2, Types.ARRAY, "MYPACKAGE.ERG_TABLE");
我现在这样做:
stmt.registerIndexTableOutParameter(2, 100, OracleTypes.VARCHAR, 100);
String[] resultArray = (String[])stmt.getPlsqlIndexTable(2);
就这些。希望这能帮助其他人。谢谢。我试过这个,效果很好。但您是否有使用“registerIndexTableOutParameter”和“getOraclePlsqlIndexTable”的经验?在我看来,这也有可能访问关联数组。我错了吗?谢谢。我试过这个,效果很好。但您是否有使用“registerIndexTableOutParameter”和“getOraclePlsqlIndexTable”的经验?在我看来,这也有可能访问关联数组。我错了吗?