网站首页  |   业界社区  |  电信社区  |  技术社区   |  极客社区  |  游戏社区  |  生活社区   |   科技博客  |   同事录
TechWeb-技术社区



标题: [推荐] PL/SQL - 嵌套游标 cursor
淋雨了
TW高级会员
Rank: 4



UID 80710
精华 29
积分 842
帖子 389
阅读权限 50
注册 2006-8-8
状态 离线
发表于 2008-7-4 15:10 资料 短消息 加为好友
PL/SQL - 嵌套游标 cursor

cursor() 函数可以将一个查询结果集封装成一个类似 REF CURSOR 的游标变量,可以 FETCH 记录,也可以作为 REF CURSOR 类型的参数进行传递。它被称为“嵌套游标(nested cursor)”。*T%d3z!F#w"h,t Z
        1. FETCH 记录
4j#T5W,@&Q g0U9{;m"j        我们先看一下测试表 test1 和 test2 的数据:
"x(g;p/Q(o2n'a'l5\TechWeb-技术社区 +K7E9o3r%R:w,}
SQL> select * from test1;
/L-M1}%q!B$| I `'{)O;Z
0E,@4^1P e"D/~0Z$]9^         ATechWeb-技术社区8^7f#v'_.D%G Q;v
----------
%b7t2y5P/@:d'V0c程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛         1程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛!W2{3p4^"F&C*o
         1tech.techweb.com.cn-`"B/x7_:R/_,F#|
         2tech.techweb.com.cn6C(}9a;\%{&`
         3tech.techweb.com.cn!w)@'?!g/A/m*p

3e2{'v'c$j2pTechWeb-技术社区SQL> select * from test2;
5O6_2F2r1{$k!D *I&I.O)}/H4f
        ID NAMETechWeb-技术社区%d6z6V(L/Y$[
---------- ------------------------------------------
4q&v:?-|#?0uTechWeb-技术社区         1 yuechaotian1TechWeb-技术社区+@6g/_0O%V:P%t&{
         2 yuechaotian2
-]$D2z(K*E-M4J"c9i6O         3 yuechaotian3$Q6k3O&|3G&m"]5k
         4 yuechaotian4TechWeb-技术社区4e:I4e!r.[3J;c9l7H$y+g"V
         5 yuechaotian5 TechWeb-技术社区0?*}.q;X8@+a7t/R
/e f#m4k(b)U&i!Y9Z4[
(@$y4I/|7Y7A&d0Q'N3V
  我们可能会发出这样一个查询:#R:a%[2a.]"F)V

7Z1a9F7X%F'J.BSQL> select id, name, (select a from test1 where a = test2.id)4E6e.]2l+K;W!H%R
  2    from test2;
:z4i0N)e3A)n7u"x'Q-\(qtech.techweb.com.cnselect id, name, (select a from test1 where a = test2.id)
%A;~!{0_8T1U3M9u,dTechWeb-技术社区                  *!t$O(a"E:k6j
ERROR 位于第 1 行:6e6I"b1B5{)n.q:W
ORA-01427: 单行子查询返回多个行
.n$y9\6l/l(T.?6?)\程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛
"k'S#b&`2| \8k 程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛'Q,r0e0z'~#R
  因为表 test1 中有两条 a=1 的记录,所以这个查询执行失败了。但有时候我们确实需要这样的查询,怎么办呢?你可以试试 cursor() 函数:TechWeb-技术社区 q%e8P'[#]0r0e8N
程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛$J5v4[&s a0R:y
SQL> set serveroutput on
8u2A1j+i!B:fSQL> declare
7a4}3g&w5K4[/K  2    cursor cur_test2 is
,[,c5w5{3Q0h*@7B4k9I程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛  3      select id, name, cursor(select a from test1 where a = test2.id)
C*e#@7m1M/m"]+@tech.techweb.com.cn  4        from test2;
*K;c${8X0Q程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛  5    rec_test2 test2%rowtype;
8k4Y4^/|9}&M!g:h6d  6
1Q)N+_(k7v7c  7    cur_test1 sys_refcursor;
+W0t;v)r+o8n;i2f/]  8    rec_test1 test1%rowtype;程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛:k"M)k6p8x&?
  9  begin&S:N c5d)q!O
10    open cur_test2; S+Y5^"_'C'@
11    loop
*@*A$W(H3s"o3b 12      fetch cur_test2 into rec_test2.id, rec_test2.name, cur_test1;
*p)`(^ e J(z)D9e1j%a 13      exit when cur_test2%notfound;
&}.F5M;C2M 14      dbms_output.put_line('rec_test2.id: ' || rec_test2.id || ' | rec_test2.name: ' || rec_test2.name);)e1H O4b;{#p#W0t,T-P
15      -- 这里不需要再显式 OPEN 游标 cur_test1,也不需要显式关闭,f0U3@$];S J6j8v,z;K
16      loopTechWeb-技术社区)S1H5})q(z&Y8H
17        fetch cur_test1 into rec_test1;
/i7L5x+b9c"N;]tech.techweb.com.cn 18        exit when cur_test1%notfound;程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛%n;F'\4L2x4G;Q
19        dbms_output.put_line( 'rec_test1.a: ' || rec_test1.a );
&i:t:T,b#h/p,n;p 20      end loop;
1A;Y7[!r!~2i:e f程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛 21    end loop;TechWeb-技术社区:]8h,A3L;X(y;V:?'H
22    close cur_test2;2G!W"[,W*_&}
23  end;
1v o*a)`6g;l3y4H4V v 24  /
5s)V r&A+U程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛rec_test2.id: 1 | rec_test2.name: yuechaotian1
4E$M0C;C+M!h"I#~:g f1xtech.techweb.com.cnrec_test1.a: 1
2}+W2i2Q4x+{;t#u&}(a }rec_test1.a: 1
1Y7H(O!r9F3h7m3?'T*c程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛rec_test2.id: 2 | rec_test2.name: yuechaotian2
)Z4o(N6V!@/]2U d;Wrec_test1.a: 2
%W$_0~&C:c8E;k$y'xrec_test2.id: 3 | rec_test2.name: yuechaotian3
*m:P ~8R&n$e4utech.techweb.com.cnrec_test1.a: 3
6K"D.G3k5Q&G3drec_test2.id: 4 | rec_test2.name: yuechaotian4程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛7H9E9h&h7O"h*N.u
rec_test2.id: 5 | rec_test2.name: yuechaotian5
0V:}.v)A&S4_-l;p6Y ,k3q2q6n2E;]0X3W
PL/SQL 过程已成功完成。

引用 回复 顶部
淋雨了
TW高级会员
Rank: 4



UID 80710
精华 29
积分 842
帖子 389
阅读权限 50
注册 2006-8-8
状态 离线
发表于 2008-7-4 15:10 资料 短消息 加为好友
  怎么样?达到你的目的了吧。我们再看一个嵌套了两个 cursor() 函数的例子:
7U2h$n0y#Z/Y%j:t,}&l+FTechWeb-技术社区
1{&?3]7u/^.j"?+|SQL> declare程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛9H3M,])b"[6?$p6n
  2    -- 嵌套定义游标
/^#D5b#i D k%a0O  3    cursor cur_test2 is&_,v7D8P.G+l G/V }4o
  4      select id, name, cursor(select a, cursor(select * from dual)
+r+A c0r.f4~*`TechWeb-技术社区  5                                          from test1TechWeb-技术社区.x"?!N%[*q
  6                                        where test1.a = test2.id)TechWeb-技术社区$?3Q2l3[ Z8_/^&z+D&p
  7        from test2;
/W'M!K*p.{'d*C"W9a7J  8    cur_test1 sys_refcursor;
*f.x#w9a'D'A(G(})Vtech.techweb.com.cn  9    cur_dual  sys_refcursor;
:F:{2F8A/R/e7c程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛 10    rec_test1 test1%rowtype;/g){)a4v$}-X%W+^
11    rec_test2 test2%rowtype;"M$j8[;Z.l(M&s
12    rec_dual varchar2(10);
/H4w:{!s$A:S X 13  begin
2f(E-e!j#n,I 14    open cur_test2;
%e.r*z4z;h+T:G-s 15    loop
0W)q-b;Q$p+h;x+K1p 16      fetch cur_test2 into rec_test2.id, rec_test2.name, cur_test1;
9x%W$l3A.nTechWeb-技术社区 17      exit when cur_test2%notfound;
;s-|1S2m/u'Y$Y6Ytech.techweb.com.cn 18      dbms_output.put_line( 'rec_test2.id: ' || rec_test2.id || '   rec_test2.name: ' || rec_test2.name);tech.techweb.com.cn!r0N$`:w&p7F8L
19      -- 这里不需要再显式 OPEN 游标 cur_test1,也不需要显式关闭(]:x+^2A.e.c
20      looptech.techweb.com.cn"?;v;Z'h*g5^5e
21        fetch cur_test1 into rec_test1.a, cur_dual;TechWeb-技术社区:s.d"T)n!Y#b
22        exit when cur_test1%notfound;
+B#}9@9d%K5X 23        dbms_output.put_line( 'rec_test1.a: ' || rec_test1.a );tech.techweb.com.cn.o8m'q%|-J*}2e4\
24        -- 这里不需要再显式 OPEN 游标 cur_dual,也不需要显式关闭
&s(["N6H&s(}:E*s&Ctech.techweb.com.cn 25        loopTechWeb-技术社区4l$p8m:@2U
26          fetch cur_dual into rec_dual;TechWeb-技术社区%U(z;C;a&H c1n
27          exit when cur_dual%notfound;
&n'o/I$\8}-b 28          dbms_output.put_line( 'rec_dual: ' || rec_dual );
%t ~%u9e.B.s1O0L 29        end loop;tech.techweb.com.cn"P$y$W;t7b
30      end loop;
#}$v8K8z0M!p1} 31    end loop;%g)G+v#?5C!{9{1A0r
32    close cur_test2;TechWeb-技术社区9m*N0D'C-M0P0l
33  end;-M$?2V;_,v W:I
34  /,u6X4r)b4N(c*N9J
rec_test2.id: 1   rec_test2.name: yuechaotian1+Z"u4~%y$r6?&\*o1a7A
rec_test1.a: 1TechWeb-技术社区(N3Z3J6T$j.P1j(~'i
rec_dual: X
(}(U4s-K.P#o1Arec_test1.a: 1:`&H3u-P0Z*x0F
rec_dual: X
6z&E/g6W3g(Yrec_test2.id: 2   rec_test2.name: yuechaotian27~7g,y5o&O3L+h7I:W*E
rec_test1.a: 2,o%x:` m%M
rec_dual: X(t'p3o6t6k1Q0F
rec_test2.id: 3   rec_test2.name: yuechaotian3程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛-s+d3~3J1W,V
rec_test1.a: 3&@5k"Y"v6Y,J+E-v
rec_dual: X
(@2R#P:U:l!Y$Orec_test2.id: 4   rec_test2.name: yuechaotian4'B*R9t*\2y$k3x
rec_test2.id: 5   rec_test2.name: yuechaotian5
#~1f%|+q1j5Z5x$Q5y1Z5n%a程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛
/?"l!R,V)?8y.y+BTechWeb-技术社区PL/SQL 过程已成功完成。 2T3l9A!I1b7A;T-\

$a8g9E#n3{(J"S程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛 tech.techweb.com.cn$C*v+n4e9N4@/~1o6{0Q-r#u
        由以上例子可以看出,嵌套游标是隐式打开的。它在以下情况下被关闭:7n3v/l;v%z0\;b!K8i
        显式关闭
4T'T!u4X w3s程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛          父游标再次执行时(比如,下一次循环前,会先关闭嵌套游标,再根据新数据重新打开)
1_&X1`:q(f+T itech.techweb.com.cn          父游标关闭时
)b4Z;~9{+G%{%Ctech.techweb.com.cn          父游标退出时
5y9V6F;j)n-J-b-s7J0o+Gtech.techweb.com.cn        fetch 父游标出错时
*k4K*}*~1j:u:N;N        2. 传递参数程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛3b)j.d5q)N:z+A
        我们先看看测试表中的数据:TechWeb-技术社区%p.? q"a1S$P4R:N;p

5b c,_1S:a(~0Y程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛SQL> select * from test2;
)@9y5^8A.M*c TechWeb-技术社区(G.I"R2G1u'D$z
        ID NAME程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛#b.G/z'{7g(|
---------- ---------------------------
(w7a!h&y0b%A:G5}'C7[         1 yuechaotian1TechWeb-技术社区)X9V'V:D;X9}.\4y5i!u"n!h
         2 yuechaotian2:Y1b)F.`,~
         3 yuechaotian3程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛'y(N1t)| s;\)H3}-r
         4 yuechaotian4TechWeb-技术社区,R-O'_$P'Z
         5 yuechaotian5%C#o"X8`.k0m*j${"^
         6 yuechaotian6
.G f6Z&H4v0s'@1Q9s2r3j         7 yuechaotian7TechWeb-技术社区7O:t:h.?&F-L%Q9b
         8 yuechaotian8
2y9R*G/b1~         9 yuechaotian9
,v6s-U7|"TTechWeb-技术社区        10 yuechaotian10
5~5x9].I9}#g*}*K#]TechWeb-技术社区
4I3?,I&u6g1r7|)u/I4r已选择10行。
'x"i7|*n:n3]2n,P,G3D
"n%e h"`9Q#_([SQL> select * from test1 order by a;
%Z.\!^-J6C6e(~tech.techweb.com.cn !O"B,C&L!a1H'@,X)w
         A7F3P)B'|&\9o9P-W(n#s
----------1p2F9?(K)g/e0I9]9}
         1
,d'e4{ {(o2O"c!eTechWeb-技术社区         1tech.techweb.com.cn2Q)Z$V#b,O-A,r
         1%h+j%z6J(e.u7|6N7P
         2
0]#H0Y)A"b+U,v&Z         2TechWeb-技术社区)t!|%K5m&f)C:f'X x
         3tech.techweb.com.cn3a/u-d'U6^.T"m$F)L
         3"Q(C+H/y3f'M7E
         4
#C+_&N4q7]         5
2U7l1o!w1s(]$L+L#NTechWeb-技术社区         6程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛,B'v5c%p#c0s.d1h
8Z"R&N)G8{%O
已选择10行。

引用 回复 顶部
淋雨了
TW高级会员
Rank: 4



UID 80710
精华 29
积分 842
帖子 389
阅读权限 50
注册 2006-8-8
状态 离线
发表于 2008-7-4 15:10 资料 短消息 加为好友
  下面我要查询 test2 中的数据,查询条件是 test2.id 在 test1.a 中对应的记录数。比如我要查询表 test2.id 在 test1.a 中不存在的记录;查询表 test2.id 在test1.a 中存在1条的记录,存在2条的记录,存在3条的记录……,我可以使用嵌套游标实现:,M z3I:L1t#E6x
6F2c:C&R5I
SQL> create function f_count(cur_names in sys_refcursor) return number(D8z%y3e;k4y1L f1G
  2  is
5b"h;`/b$o/e$G fTechWeb-技术社区  3    v_name test2.name%type;
#[0w&A8Z$~'O!J"D-H;Ftech.techweb.com.cn  4    n_count number(5) := 0;
7]*A1A9]:b*v2m.l  5  begin3?2F$G6f,A"^0X
  6    loop%~'W8y:E*F%s
  7      fetch cur_names into v_name;
-b1b"n)g J%{程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛  8      exit when cur_names%notfound;
0K2l.|3b)}"N0]+c6S程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛  9      n_count := n_count + 1;
9g+V0V4O/J4i 10    end loop;#F+S4I#P)i"Q3?#t:f9G
11    return n_count;
,k,f:S:}*U'Q%G程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛 12  end f_count;+n'?4L9S M&i
13  /
$_5}%o$k:Y1@tech.techweb.com.cn
.Q$V7[3D$a;Q,v函数已创建。#m%~%n9a.|,G$h
"r4N"B8I-f,? K-G*T
SQL> select id, name.s+z'd5i3d,M'~:U7{
  2    from test2
4~)H3_']7d;@,btech.techweb.com.cn  3   where f_count( cursor( select a from test1 where a = test2.id ) ) = 1;
.X)w;D$p*h1N2`2s TechWeb-技术社区3W2L0~:h8R#f7a;K%~9m
        ID NAME3A4~-T*L*j/a
---------- ---------------------------------------------------
,d4n1y0O&X#q4_$k$x         4 yuechaotian4程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛 l5_7B&K$y&f
         5 yuechaotian5程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛5c#p1}:i9J)];i#A&n
         6 yuechaotian6
"o:\8x)i%N j;K"m
!Q+e,P+c;e*m(_3H"[9~-kTechWeb-技术社区SQL> select id, name
+A0x'C(M5p)o#B  2    from test2
1d%t9e%Z:B3K-p  3   where f_count( cursor( select a from test1 where a = test2.id ) ) = 0;tech.techweb.com.cn.i$Z"U:Q6p,K/b$b4L

8u;m7W:~ L#y6q程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛        ID NAME
%L4X1E:])]*O6|3F---------- ---------------------------------------------------TechWeb-技术社区 E"O%U$O+r.z
         7 yuechaotian7(n(s L&J1F3r/u
         8 yuechaotian8,c0B6D$H3M8k5?
         9 yuechaotian9
v/@1D4b.d3C1F R0U        10 yuechaotian10
#N7T s6}3w;B'Y (L;U w-{)B3{ l-S/`&v+}
SQL> select id, name
8K+o&d6l8|+f4}  2    from test2
4v0b6t5[7l.b&@  3   where f_count( cursor( select a from test1 where a = test2.id ) ) = 2;+[3r)y a1L&I

"E&Q*v1H+K:K3K6O5@        ID NAME&P ~9X4I0n)@6q/a;i1B
---------- ---------------------------------------------------
!w'D6m$V6z/`4|!N         2 yuechaotian2
*S&x0F4]:z/](yTechWeb-技术社区         3 yuechaotian3程序开发,操作系统,服务器,源码下载,Linux,Unix,BSD,PHP,Apach,asp,下载,源码,黑客,安全,技术社区,技术论坛'F0^7I2N:j/W2s/t:P,q&c

2A"s$l1w9o3L&rSQL> select id, name
.k2`1s5o'U*R0R  2    from test2;`,m:f%C/]0H+n"n
  3   where f_count( cursor( select a from test1 where a = test2.id ) ) = 3;,F1c2u-q0L;k
tech.techweb.com.cn0Z _,q4T-d.N/c x&^
        ID NAME%g7h+K6D'R4A
---------- ---------------------------------------------------tech.techweb.com.cn4_"h3h"w(G$M8~-v
         1 yuechaotian1

引用 回复 顶部
查看积分策略说明快速回复主题
选项 标题 Smilies
禁用 URL 识别
禁用 Smilies
禁用 Discuz!代码
使用匿名发帖
使用个人签名
接收新回复邮件通知
内容





当前时区 GMT+8, 现在时间是 2008-9-6 05:53
京ICP证060517号

本论坛支付平台由支付宝提供
携手打造安全诚信的交易社区 Powered by Discuz! 5.5.0 © 2001-2008 Comsenz Inc.
Processed in 0.053440 second(s), 7 queries

清除 Cookies - 联系我们 - TechWeb.com.cn - Archiver - WAP