【DB笔试面试466】存储过程或函数如何返回集合类型?
存储过程或函数如何返回集合类型?
♣ 答案部分
TABLE()函数可接受查询语句或游标作为输入参数,并可输出多行数据,称为表函数。所以,存储过程或函数返回集合类型主要采用的是表函数和PIPELINED函数(管道化表函数)及数组结合的方式。当然,也可以采用存储过程返回系统游标SYS_REFCURSOR或自定义游标的方式。
下面先看一个使用表函数的最简单的例子:
CREATE TABLE TEST (ID VARCHAR2(20));
INSERT INTO TEST VALUES('1');
COMMIT;
EXPLAIN PLAN FOR SELECT * FROM TEST;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
结果如下:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 12 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| TEST | 1 | 12 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
Note
-----
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
- dynamic sampling used for this statement (level=2)
可以看到,一个简单的表函数可以返回多行数据。下面再看一个TABLE()结合PIPELINED函数的例子:
CREATE OR REPLACE TYPE T_TEST AS OBJECT
(
ID INTEGER,
IN_DATE DATE,
NAME VARCHAR2(60)
);
--创建TYPE
CREATE OR REPLACE TYPE T_TEST_TABLE AS TABLE OF T_TEST;
--创建函数
CREATE OR REPLACE FUNCTION F_TEST_PIPE(N IN NUMBER DEFAULT NULL)
RETURN T_TEST_TABLE
PIPELINED AS
V_TEST T_TEST_TABLE := T_TEST_TABLE();
BEGIN
FOR I IN 1 .. NVL(N, 100) LOOP
PIPE ROW(T_TEST(I, SYSDATE, 'test' || I));
END LOOP;
RETURN;
END F_TEST_PIPE;
/
--查询
SELECT * FROM TABLE(F_TEST_PIPE(5));
SELECT * FROM THE(SELECT F_TEST_PIPE(5) FROM DUAL);
SYS@lhrdb> SELECT * FROM TABLE(F_TEST_PIPE(5));
ID IN_DATE NAME
---------- ------------------- --------
1 2017-01-05 11:42:50 test1
2 2017-01-05 11:42:50 test2
3 2017-01-05 11:42:50 test3
4 2017-01-05 11:42:50 test4
5 2017-01-05 11:42:50 test5
下面给出TABLE()结合数组的例子:
CREATE OR REPLACE TYPE T_TEST AS OBJECT
(
ID INTEGER,
IN_DATE DATE,
NAME VARCHAR2(60)
)
;
CREATE OR REPLACE TYPE T_TEST_TABLE AS TABLE OF T_TEST;
CREATE OR REPLACE FUNCTION F_TEST_ARRAY(N IN NUMBER DEFAULT NULL)
RETURN T_TEST_TABLE AS
V_TEST T_TEST_TABLE := T_TEST_TABLE();
BEGIN
FOR I IN 1 .. NVL(N, 100) LOOP
V_TEST.EXTEND();
V_TEST(V_TEST.COUNT) := T_TEST(I, SYSDATE, 'TEST' || I);
END LOOP;
RETURN V_TEST;
END F_TEST_ARRAY;
/
SELECT * FROM TABLE(F_TEST_ARRAY(5));
SELECT * FROM THE(SELECT F_TEST_ARRAY(5) FROM DUAL);
SYS@lhrdb> SELECT * FROM TABLE(F_TEST_ARRAY(5));
ID IN_DATE NAME
---------- ------------------- ----------------------
1 2017-01-05 11:48:50 TEST1
2 2017-01-05 11:48:50 TEST2
3 2017-01-05 11:48:50 TEST3
4 2017-01-05 11:48:50 TEST4
5 2017-01-05 11:48:50 TEST5
下面来看使用存储过程如何返回游标。下面的例子是返回一个系统游标SYS_REFCURSOR:
CREATE OR REPLACE PROCEDURE P_CURSOR_TLHR(CUR_ARG OUT SYS_REFCURSOR) AS
BEGIN
OPEN CUR_ARG FOR
SELECT * FROM USER_TABLES WHERE ROWNUM < 5;
END;
--调用测试
DECLARE
VARCURSOR SYS_REFCURSOR;
R USER_TABLES%ROWTYPE;
BEGIN
P_CURSOR_TLHR(VARCURSOR); --这样这个游标就有值了
LOOP
FETCH VARCURSOR
INTO R;
EXIT WHEN VARCURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(R.TABLE_NAME);
END LOOP;
END;
当然,P_CURSOR_TLHR也可以返回多个系统游标,需要设置多个OUT类型的参数。
下面的例子返回自定义游标:
--定义全局变量
CREATE OR REPLACE PACKAGE pkg_package AS
TYPE type_cursor IS REF CURSOR;
TYPE type_record IS RECORD(
table_name VARCHAR2(32),
TABLESPACE_NAME VARCHAR2(32)
);
END;
--创建返回游标的存储过程
CREATE OR REPLACE PROCEDURE P_TEMP_PROCEDURE(CUR_OUT_ARG OUT PKG_PACKAGE.TYPE_CURSOR) IS
BEGIN
OPEN CUR_OUT_ARG FOR
SELECT D.TABLE_NAME, D.TABLESPACE_NAME
FROM USER_TABLES D
WHERE ROWNUM <= 5;
END;
--调用
DECLARE
cur_out_arg pkg_package.type_cursor;
rec_arg pkg_package.type_record;
BEGIN
p_temp_procedure(cur_out_arg);
FETCH cur_out_arg
INTO rec_arg;
dbms_output.put_line(rec_arg.table_name);
dbms_output.put_line(rec_arg.TABLESPACE_NAME);
END;
下面给出一个函数返回系统游标的例子:
CREATE OR REPLACE FUNCTION F_GET_SYS_REFCURSOR_LHR(P_EMPNO NUMBER) RETURN SYS_REFCURSOR IS
CUR_SYS SYS_REFCURSOR;
BEGIN
OPEN CUR_SYS FOR
SELECT LEVEL P_LEVEL,
T.EMPNO,
T.ENAME,
T.MGR,
(LPAD(' ', 6 * (LEVEL - 1)) || LEVEL || ':' || T.ENAME || '(' ||
T.EMPNO || ')') NAME_ALL,
SUBSTR(SYS_CONNECT_BY_PATH(T.ENAME, '=>'), 3) ALL_NAME_LEVEL,
CONNECT_BY_ROOT(T.ENAME) ROOT,
DECODE(CONNECT_BY_ISLEAF, 1, 'Y', 0, 'N') IS_LEAF
FROM SCOTT.EMP T
START WITH T.EMPNO=P_EMPNO
CONNECT BY NOCYCLE MGR = PRIOR EMPNO;
RETURN CUR_SYS;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
查询:
SELECT F_GET_SYS_REFCURSOR_LHR(7566) FROM DUAL;
结果如下所示:
有关存储过程或函数返回集合类型的写法有多种,作者把这多种方式写成了一个包,已发布到博客(地址:http://blog.itpub.net/26736162/viewspace-2131977/)和公众号上,读者可自行下载阅读。
本文选自《Oracle程序员面试笔试宝典》,作者:李华荣。
---------------优质麦课------------
详细内容可以添加麦老师微信或QQ私聊。
● 本文作者:小麦苗,只专注于数据库的技术,更注重技术的运用
● 作者博客地址:http://blog.itpub.net/26736162/abstract/1/
● 本系列题目来源于作者的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
● 版权所有,欢迎分享本文,转载请保留出处
● QQ:646634621 QQ群:618766405
● 提供OCP、OCM和高可用部分最实用的技能培训
● 题目解答若有不当之处,还望各位朋友批评指正,共同进步
长按下图识别二维码或微信扫描下图二维码来关注小麦苗的微信公众号:xiaomaimiaolhr,学习最实用的数据库技术。
本文分享自微信公众号 - DB宝(lhrdba)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
- 【DB笔试面试436】Oracle中如何导出存储过程、函数、包和触发器的定义语句?如何导出表的结构?如何导出索引的创建语句?
- PKG_COLLECTION_LHR 存储过程或函数返回集合类型
- 【DB笔试面试357】在Oracle数据库中,如何捕获存储过程中出现异常的行号?
- 在COM/DCOM中如何将数组作为函数返回的类型传递
- 【DB笔试面试825】在Oracle中,如何获取ADDM报告?
- 如何设置IQueryable的类型为函数返回的类型??
- 仅返回类型不同的函数,在C++中如何实现重载?
- Wind函数返回的list类型如何转换为数组
- nutz返回类的集合如何设置和获取返回值类型
- 【DB笔试面试628】Oracle的统计信息包括哪几种类型?
- 关于C#间接继承的一些思考:如何修改继承函数的返回值类型
- 【DB笔试面试238】在Oracle中,如何将信息写入Oracle的告警日志中?
- c/c++笔试题——const类型的成员函数内部如何改变成员变量
- 【DB笔试面试857】在Oracle中,若一个主机上有多个Oracle实例,则如何确定哪些共享内存段属于想要清掉的实例的内存段?
- 编程拾遗:集合类型的函数,返回值,如果没有,就返回默认集合new,或者 default(T)好一些。
- Mybatis——返回类型为 集合嵌套集合 应该如何处理
- 【DB笔试面试856】在Oracle中,如何判定实例是否运行?
- 【DB笔试面试246】在Oracle中,如何修改数据库的DBID和DBNAME?
- 【DB笔试面试458】在Oracle中,如何判断一个字符串是否全为数字?
- 【DB笔试面试496】如何让程序等待60秒钟后继续运行?