CREATE OR REPLACE PACKAGE Pkg_Test IS TYPE Type_Job_Row IS RECORD( Job_Code VARCHAR(50), Job_Name VARCHAR(200)); TYPE Type_Job_Table IS TABLE OF Type_Job_Row; TYPE Type_Result_Table IS REF CURSOR; PROCEDURE Sp_Get_Job_Info(Result_Table OUT Type_Result_Table);END Pkg_Test;
/
CREATE OR REPLACE PACKAGE BODY Pkg_Test IS PROCEDURE Sp_Get_Job_Info(Result_Table OUT Type_Result_Table) IS Job_Table Type_Job_Table := Type_Job_Table(); Job_Row Type_Job_Row; BEGIN Job_Row.Job_Code := 'A'; Job_Row.Job_Name := 'A12123'; Job_Table.EXTEND(); Job_Table(Job_Table.COUNT) := Job_Row; Job_Row.Job_Code := 'B'; Job_Row.Job_Name := 'B12123'; Job_Table.EXTEND(); Job_Table(Job_Table.COUNT) := Job_Row; Dbms_Output.Put_Line(Job_Table.COUNT); --OUTPUT RESULT IS 2 --The following code can not compile succeeded --OPEN result_table for -- select * from table(JOB_ROWS) ; END; PROCEDURE Sp_Get_Job_Info_2(In_Job_Id IN NUMBER, Result_Table OUT Type_Result_Table) IS Job_Table Type_Job_Table := Type_Job_Table(); Job_Row Type_Job_Row; CURSOR Cursor_Jobs IS SELECT * FROM Employee_Jobs WHERE Job_Id >= In_Job_Id; BEGIN FOR r_Job IN Cursor_Jobs LOOP Job_Row.Job_Code := r_Job.Job_Code; Job_Row.Job_Name := r_Job.Job_Name; Job_Table.EXTEND(); Job_Table(Job_Table.COUNT) := Job_Row; END LOOP; Dbms_Output.Put_Line(Job_Table.COUNT); --OUTPUT RESULT IS 2 --The following code can not compile succeeded --OPEN result_table for -- select * from table(JOB_ROWS) ; END;END Pkg_Test;/
在上面的例子中, 我们在package中声明了一个record类型(TYPE_JOB_ROW)和一个table类型(TYPE_JOB_TABLE), 在存储过程SP_GET_JOB_INFO中, 可以实例化这个table类型变量JOB_TABLE, 你可以向JOB_TABLE插入单个的记录. 如果使用Loop语句的话, 你可以批量地插入许多记录到这个表变量中, 就像存储过程SP_GET_JOB_INFO2.
这种在package中定义的table类型变量, 对于一般的DML操作是非常实用的, 但如果你要将table表变量的结果作为ref cursor类型的存储过程out参数暴露出来, 就不行了. 在上面的示例代码中, 如果将取消最后两句代码的注释, 你就发现这个存储过程不能被编译. 为什么呢? 详见 http://forums.oracle.com/forums/thread.jspa?threadID=623197
简单讲, 原因就是, 我们是在package中定义的TYPE_JOB_TABLE的table类型, 这个类型对于该package之外其实是不可见的, 而存储过程却要将这个表类型暴露到package之外, 所以Oracle会报错. 知道这个原因之后, 解决也很简单, Record和Table的定义放在包之外, 就行了. 需要说明的是, 需要修改一下Record的定义格式(从Record类型改到Object类型).
--create one object type outside of one package
create or replace type TYPE_JOB_ROW as object
(
JOB_CODE VARCHAR(50),
JOB_NAME VARCHAR(200)
);
--create one table type outside of one package
CREATE OR REPLACE TYPE TYPE_JOB_TABLE is TABLE OF TYPE_JOB_ROW;
create or replace package PKG_TEST2 is
type type_result_table is ref cursor ;
procedure SP_GET_JOB_INFO(result_table out type_result_table) ;
end PKG_TEST2;
/
create or replace package body PKG_TEST2 is
procedure SP_GET_JOB_INFO(result_table out type_result_table)
IS
JOB_TABLE TYPE_JOB_TABLE:=TYPE_JOB_TABLE() ;
JOB_ROW TYPE_JOB_ROW ;
BEGIN
JOB_ROW:=TYPE_JOB_ROW(JOB_CODE => 'A',JOB_NAME => 'A123') ;
JOB_ROW.JOB_NAME:='A12' ; --Change the job_name from A123->A12
JOB_TABLE.extend();
JOB_TABLE(JOB_TABLE.count) := JOB_ROW ;
OPEN result_table FOR
SELECT * FROM table(JOB_TABLE) ;
END ;
end PKG_TEST2;