使用 java 以 table 对象作为输入调用 oracle 存储过程
calling oracle stored procedure with table object as input using java
我尝试使用 4 个参数 1 作为自定义类型的输入调用 oracle 存储过程 table 并得到以下错误
PriceInBundle_Input_Table
是一个有两个元素的对象
材料编号 nvarchar2(22),
BundleNumber nvarchar2(22)
java.sql.SQLException: ORA-03115: unsupported network datatype or representation
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:204)
at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:1034)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1329)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3685)
at oracle.jdbc.driver.OracleCallableStatement.execute(OracleCallableStatement.java:4694)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1088)
at com.wincash.test.service.PriceInBundle.getPriceInBundle(PriceInBundle.java:33)
at com.wincash.test.Wincash.main(Wincash.java:10)
这是我尝试调用的存储过程
create or replace PROCEDURE GET_PRICE_IN_BUNDLE(
P_IN_PriceInBundle_Input IN PriceInBundle_Input_Table,
P_OUT_PriceInBundle_Output OUT PriceInBundle_Output_Table,
P_OUT_RETURN_CODE OUT NUMBER,
P_OUT_RETURN_MESSAGE OUT VARCHAR2 )
AS
V_PRICE NUMBER:=-1;
V_Count_Article NUMBER:=-1;
V_Count_Bundle NUMBER:=-1;
V_Count_Matset NUMBER :=-1;
BEGIN
P_OUT_RETURN_CODE := -200;
P_OUT_RETURN_MESSAGE :='Initial';
P_OUT_PriceInBundle_Output := PriceInBundle_Output_Table();
FOR item_record_index IN P_IN_PriceInBundle_Input.FIRST .. P_IN_PriceInBundle_Input.LAST
LOOP
P_OUT_PriceInBundle_Output.EXTEND ;
P_OUT_PriceInBundle_Output(item_record_index) := PriceInBundle_Output_Record('','',-1,-1,'');
P_OUT_PriceInBundle_Output(item_record_index).MaterialNumber := P_IN_PriceInBundle_Input(item_record_index).MaterialNumber ;
P_OUT_PriceInBundle_Output(item_record_index).BundleNumber := P_IN_PriceInBundle_Input(item_record_index).BundleNumber ;
V_PRICE :=-1;
BEGIN
SELECT MAX(PRICE)
INTO V_PRICE
FROM matset
WHERE compid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status<>'D'
)
AND matid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).BundleNumber
AND status<>'D'
)
AND status <>'D';
IF V_PRICE IS NOT NULL THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := V_PRICE;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode :=0;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='SUCCESS';
ELSE
SELECT COUNT(*)
INTO V_Count_Matset
FROM matset
WHERE compid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status<>'D'
)
AND matid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).BundleNumber
AND status<>'D'
)
AND status <>'D';
IF V_Count_Matset>0 THEN
SELECT MAX(price)
INTO V_PRICE
FROM material
WHERE matno =P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status ='A';
P_OUT_PriceInBundle_Output(item_record_index).Price := V_PRICE;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode :=0;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Success';
ELSE
SELECT COUNT(*)
INTO V_Count_Article
FROM material
WHERE matno = P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status ='A';
IF V_Count_Article =0 THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -2;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Wrong Article Number';
ELSE
SELECT COUNT(*)
INTO V_Count_Bundle
FROM material
WHERE matno = P_IN_PriceInBundle_Input(item_record_index).BundleNumber
AND status ='A';
IF V_Count_Bundle =0 THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -3;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Wrong Bundle Number';
ELSE
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -4;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Article does not belong to bundle';
END IF;
END IF;
END IF;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -4 ;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage := 'Invalid Input,No price found' ;
WHEN OTHERS THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -100 ;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage :='UNKNOWN ERROR ' ||SQLERRM ;
END ;
END LOOP;
P_OUT_RETURN_CODE := 0 ;
P_OUT_RETURN_MESSAGE := 'Success' ;
EXCEPTION
WHEN OTHERS THEN
P_OUT_RETURN_CODE := -100 ;
P_OUT_RETURN_MESSAGE :='UNKNOWN ERROR ' ||SQLERRM ;
END;
我尝试使用以下 java 代码进行呼叫
import com.wincash.test.config.DBConnection;
import oracle.jdbc.OracleCallableStatement;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
public class PriceInBundle {
private static Logger logger= Logger.getLogger(PriceInBundle.class);
private static Connection conn=null;
private static OracleCallableStatement callStatement=null;
public Boolean getPriceInBundle() {
Boolean rs=Boolean.FALSE;
conn=DBConnection.getConnection();
try {
Object [] table= new Object[2];
ArrayDescriptor priceInBundleTable= ArrayDescriptor.createDescriptor("PRICEINBUNDLE_INPUT_TABLE", conn);
ARRAY priceInTable= new ARRAY(priceInBundleTable, conn, table);
callStatement=(OracleCallableStatement)conn.prepareCall("{call GET_PRICE_IN_BUNDLE(?,?,?,?)}");
callStatement.setARRAY(1, priceInTable);
callStatement.registerOutParameter(2, java.sql.Types.ARRAY);
callStatement.registerOutParameter(3, java.sql.Types.NUMERIC);
callStatement.registerOutParameter(4, java.sql.Types.VARCHAR);
rs=callStatement.execute();
} catch (SQLException e) {
// logger.info(e.getMessage());
e.printStackTrace();
}finally {
try {
conn.close();
callStatement.close();
} catch (SQLException e) {
logger.info(e.getMessage());
}
}
return rs;
}
}
请大家多多支持
我找到了解决方案 只需将 oracle 自定义类型添加到输出参数,如以下代码
将此代码更改为
callStatement.registerOutParameter(2, java.sql.Types.ARRAY);
到
callStatement.registerOutParameter(2, java.sql.Types.ARRAY,"PRICEINBUNDLE_OUTPUT_TABLE");
由于 Marmite Bomber 的评论
,问题已解决
我尝试使用 4 个参数 1 作为自定义类型的输入调用 oracle 存储过程 table 并得到以下错误
PriceInBundle_Input_Table
是一个有两个元素的对象
材料编号 nvarchar2(22),
BundleNumber nvarchar2(22)
java.sql.SQLException: ORA-03115: unsupported network datatype or representation
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:204)
at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:1034)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1329)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3685)
at oracle.jdbc.driver.OracleCallableStatement.execute(OracleCallableStatement.java:4694)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1088)
at com.wincash.test.service.PriceInBundle.getPriceInBundle(PriceInBundle.java:33)
at com.wincash.test.Wincash.main(Wincash.java:10)
这是我尝试调用的存储过程
create or replace PROCEDURE GET_PRICE_IN_BUNDLE(
P_IN_PriceInBundle_Input IN PriceInBundle_Input_Table,
P_OUT_PriceInBundle_Output OUT PriceInBundle_Output_Table,
P_OUT_RETURN_CODE OUT NUMBER,
P_OUT_RETURN_MESSAGE OUT VARCHAR2 )
AS
V_PRICE NUMBER:=-1;
V_Count_Article NUMBER:=-1;
V_Count_Bundle NUMBER:=-1;
V_Count_Matset NUMBER :=-1;
BEGIN
P_OUT_RETURN_CODE := -200;
P_OUT_RETURN_MESSAGE :='Initial';
P_OUT_PriceInBundle_Output := PriceInBundle_Output_Table();
FOR item_record_index IN P_IN_PriceInBundle_Input.FIRST .. P_IN_PriceInBundle_Input.LAST
LOOP
P_OUT_PriceInBundle_Output.EXTEND ;
P_OUT_PriceInBundle_Output(item_record_index) := PriceInBundle_Output_Record('','',-1,-1,'');
P_OUT_PriceInBundle_Output(item_record_index).MaterialNumber := P_IN_PriceInBundle_Input(item_record_index).MaterialNumber ;
P_OUT_PriceInBundle_Output(item_record_index).BundleNumber := P_IN_PriceInBundle_Input(item_record_index).BundleNumber ;
V_PRICE :=-1;
BEGIN
SELECT MAX(PRICE)
INTO V_PRICE
FROM matset
WHERE compid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status<>'D'
)
AND matid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).BundleNumber
AND status<>'D'
)
AND status <>'D';
IF V_PRICE IS NOT NULL THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := V_PRICE;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode :=0;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='SUCCESS';
ELSE
SELECT COUNT(*)
INTO V_Count_Matset
FROM matset
WHERE compid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status<>'D'
)
AND matid IN
(SELECT gid
FROM material
WHERE matno= P_IN_PriceInBundle_Input(item_record_index).BundleNumber
AND status<>'D'
)
AND status <>'D';
IF V_Count_Matset>0 THEN
SELECT MAX(price)
INTO V_PRICE
FROM material
WHERE matno =P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status ='A';
P_OUT_PriceInBundle_Output(item_record_index).Price := V_PRICE;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode :=0;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Success';
ELSE
SELECT COUNT(*)
INTO V_Count_Article
FROM material
WHERE matno = P_IN_PriceInBundle_Input(item_record_index).MaterialNumber
AND status ='A';
IF V_Count_Article =0 THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -2;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Wrong Article Number';
ELSE
SELECT COUNT(*)
INTO V_Count_Bundle
FROM material
WHERE matno = P_IN_PriceInBundle_Input(item_record_index).BundleNumber
AND status ='A';
IF V_Count_Bundle =0 THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -3;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Wrong Bundle Number';
ELSE
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -4;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage:='Article does not belong to bundle';
END IF;
END IF;
END IF;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -4 ;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage := 'Invalid Input,No price found' ;
WHEN OTHERS THEN
P_OUT_PriceInBundle_Output(item_record_index).Price := -1;
P_OUT_PriceInBundle_Output(item_record_index).ResultCode := -100 ;
P_OUT_PriceInBundle_Output(item_record_index).ResultMessage :='UNKNOWN ERROR ' ||SQLERRM ;
END ;
END LOOP;
P_OUT_RETURN_CODE := 0 ;
P_OUT_RETURN_MESSAGE := 'Success' ;
EXCEPTION
WHEN OTHERS THEN
P_OUT_RETURN_CODE := -100 ;
P_OUT_RETURN_MESSAGE :='UNKNOWN ERROR ' ||SQLERRM ;
END;
我尝试使用以下 java 代码进行呼叫
import com.wincash.test.config.DBConnection;
import oracle.jdbc.OracleCallableStatement;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
public class PriceInBundle {
private static Logger logger= Logger.getLogger(PriceInBundle.class);
private static Connection conn=null;
private static OracleCallableStatement callStatement=null;
public Boolean getPriceInBundle() {
Boolean rs=Boolean.FALSE;
conn=DBConnection.getConnection();
try {
Object [] table= new Object[2];
ArrayDescriptor priceInBundleTable= ArrayDescriptor.createDescriptor("PRICEINBUNDLE_INPUT_TABLE", conn);
ARRAY priceInTable= new ARRAY(priceInBundleTable, conn, table);
callStatement=(OracleCallableStatement)conn.prepareCall("{call GET_PRICE_IN_BUNDLE(?,?,?,?)}");
callStatement.setARRAY(1, priceInTable);
callStatement.registerOutParameter(2, java.sql.Types.ARRAY);
callStatement.registerOutParameter(3, java.sql.Types.NUMERIC);
callStatement.registerOutParameter(4, java.sql.Types.VARCHAR);
rs=callStatement.execute();
} catch (SQLException e) {
// logger.info(e.getMessage());
e.printStackTrace();
}finally {
try {
conn.close();
callStatement.close();
} catch (SQLException e) {
logger.info(e.getMessage());
}
}
return rs;
}
}
请大家多多支持
我找到了解决方案
callStatement.registerOutParameter(2, java.sql.Types.ARRAY);
到
callStatement.registerOutParameter(2, java.sql.Types.ARRAY,"PRICEINBUNDLE_OUTPUT_TABLE");
由于 Marmite Bomber 的评论
,问题已解决