cursor() 函数可以将一个查询结果集封装成一个类似 REF CURSOR 的游标变量可以 FETCH 记录也可以作为 REF CURSOR 类型的参数进行传递它被称为嵌套游标(nested cursor)
FETCH 记录
我们先看一下测试表 test 和 test 的数据
SQL> select * from test;
A
SQL> select * from test;
ID NAME
yuechaotian
yuechaotian
yuechaotian
yuechaotian
yuechaotian
我们可能会发出这样一个查询
SQL> select id name (select a from test where a = testid)
from test;
select id name (select a from test where a = testid)
*
ERROR 位于第 行:
ORA: 单行子查询返回多个行
因为表 test 中有两条 a= 的记录所以这个查询执行失败了但有时候我们确实需要这样的查询怎么办呢?你可以试试 cursor() 函数
SQL> set serveroutput on
SQL> declare
cursor cur_test is
select id name cursor(select a from test where a = testid)
from test;
rec_test test%rowtype;
cur_test sys_refcursor;
rec_test test%rowtype;
begin
open cur_test;
loop
fetch cur_test into rec_testid rec_testname cur_test;
exit when cur_test%notfound;
dbms_outputput_line(rec_testid: || rec_testid || | rec_testname: || rec_testname);
这里不需要再显式 OPEN 游标 cur_test也不需要显式关闭
loop
fetch cur_test into rec_test;
exit when cur_test%notfound;
dbms_outputput_line( rec_testa: || rec_testa );
end loop;
end loop;
close cur_test;
end;
/
rec_testid: | rec_testname: yuechaotian
rec_testa:
rec_testa:
rec_testid: | rec_testname: yuechaotian
rec_testa:
rec_testid: | rec_testname: yuechaotian
rec_testa:
rec_testid: | rec_testname: yuechaotian
rec_testid: | rec_testname: yuechaotian
PL/SQL 过程已成功完成
怎么样?达到你的目的了吧我们再看一个嵌套了两个 cursor() 函数的例子
SQL> declare
嵌套定义游标
cursor cur_test is
select id name cursor(select a cursor(select * from dual)
from test
where testa = testid)
from test;
cur_test sys_refcursor;
cur_dual sys_refcursor;
rec_test test%rowtype;
rec_test test%rowtype;
rec_dual varchar();
begin
open cur_test;
loop
fetch cur_test into rec_testid rec_testname cur_test;
exit when cur_test%notfound;
dbms_outputput_line( rec_testid: || rec_testid || rec_testname: || rec_testname);
这里不需要再显式 OPEN 游标 cur_test也不需要显式关闭
loop
fetch cur_test into rec_testa cur_dual;
exit when cur_test%notfound;
dbms_outputput_line( rec_testa: || rec_testa );
这里不需要再显式 OPEN 游标 cur_dual也不需要显式关闭
loop
fetch cur_dual into rec_dual;
exit when cur_dual%notfound;
dbms_outputput_line( rec_dual: || rec_dual );
end loop;
end loop;
end loop;
close cur_test;
end;
/
rec_testid: rec_testname: yuechaotian
rec_testa:
rec_dual: X
rec_testa:
rec_dual: X
rec_testid: rec_testname: yuechaotian
rec_testa:
rec_dual: X
rec_testid: rec_testname: yuechaotian
rec_testa:
rec_dual: X
rec_testid: rec_testname: yuechaotian
rec_testid: rec_testname: yuechaotian
PL/SQL 过程已成功完成
由以上例子可以看出嵌套游标是隐式打开的它在以下情况下被关闭
显式关闭
父游标再次执行时(比如下一次循环前会先关闭嵌套游标再根据新数据重新打开)
父游标关闭时
父游标退出时
fetch 父游标出错时
传递参数
我们先看看测试表中的数据
SQL> select * from test;
ID NAME
yuechaotian
yuechaotian
yuechaotian
yuechaotian
yuechaotian
yuechaotian
yuechaotian
yuechaotian
yuechaotian
yuechaotian
已选择行
SQL> select * from test order by a;
A
已选择行
下面我要查询 test 中的数据查询条件是 testid 在 testa 中对应的记录数比如我要查询表 testid 在 testa 中不存在的记录查询表 testid 在testa 中存在条的记录存在条的记录存在条的记录……我可以使用嵌套游标实现
SQL> create function f_count(cur_names in sys_refcursor) return number
is
v_name testname%type;
n_count number() := ;
begin
loop
fetch cur_names into v_name;
exit when cur_names%notfound;
n_count := n_count + ;
end loop;
return n_count;
end f_count;
/
函数已创建
SQL> select id name
from test
where f_count( cursor( select a from test where a = testid ) ) = ;
ID NAME
yuechaotian
yuechaotian
yuechaotian
SQL> select id name
from test
where f_count( cursor( select a from test where a = testid ) ) = ;
ID NAME
yuechaotian
yuechaotian
yuechaotian
yuechaotian
SQL> select id name
from test
where f_count( cursor( select a from test where a = testid ) ) = ;
ID NAME
yuechaotian
yuechaotian
SQL> select id name
from test
where f_count( cursor( select a from test where a = testid ) ) = ;
ID NAME
yuechaotian