日期:2014-05-16  浏览次数:20550 次

oracle之REF CURSOR关键词

Ref cursor属于动态cursor(直到运行时才知道这条查询)。

从技术上讲,在最基本的层次静态cursor和ref cursor是相同的。一个典型的PL/SQL光标按定义是静态的。Ref光标正好相反,可以动态地打开,或者利用一组SQL静态语句来打开,选择哪种方法由逻辑确定(一个IF/THEN/ELSE代码块将打开一个或其它的查询)。例如,下面的代码块显示一个典型的静态SQL光标,光标C。此外,还显示了如何通过使用动态SQL或静态SQL来用ref光标(在本例中为L_CURSOR)来打开一个查询:

Declare
????? type rc is ref cursor;
????? cursor c is select * from dual;
?????
????? l_cursor rc;
??? begin
????? if (to_char(sysdate,'dd') = 30) then
????????? -- ref cursor with dynamic sql
????????? open l_cursor for 'select * from emp';
????? elsif (to_char(sysdate,'dd') = 29) then
????????? -- ref cursor with static sql
????????? open l_cursor for select * from dept;
????? else
?????????? -- with ref cursor with static sql
?????????? open l_cursor for select * from dual;
????? end if;
????? -- the "normal" static cursor
????? open c;
??? end;
??? /

在这段代码块中,可以看到了最显而易见的区别:无论运行多少次该代码块,光标C总是select * from dual。相反,ref光标可以是任何结果集,因为"select * from emp"字符串可以用实际上包含任何查询的变量来代替。

?
普通cursor与REF cursor还有一些大家应该都熟悉的区别

1)PL/SQL静态光标不能返回到客户端,只有PL/SQL才能利用它。ref光标能够被返回到客户端,这就是从Oracle的存储过程返回结果集的方式。

2)PL/SQL静态光标可以是全局的,而ref光标则不是。 也就是说,不能在包说明或包体中的过程或函数之外定义ref光标。 只能在定义ref光标的过程中处理它,或返回到客户端应用程序。

3)ref光标可以从子例程传递到子例程,而光标则不能。 为了共享静态光标,必须在包说明或包体中把它定义为全局光标。 因为使用全局变量通常不是一种很好的编码习惯,因此可以用ref光标来共享PL/SQL中的光标,无需混合使用全局变量。

最后,使用静态光标--通过静态SQL(但不用ref光标)--比使用ref光标效率高,而ref光标的使用仅限于以下几种情况:

把结果集返回给客户端;
在多个子例程之间共享光标(实际上与上面提到的一点非常类似);
没有其他有效的方法来达到你的目标时,则使用ref光标,正如必须用动态SQL时那样;

简言之,首先考虑使用静态SQL,只有绝对必须使用ref光标时才使用ref光标,也有人建议尽量使用隐式游标,避免编写附加的游标控制代码(声明,打开,获取,关闭),也不需要声明变量来保存从游标中获取的数据。这个就因人因具体的case大家去酌定吧。

?

http://www.itpub.net/443352.html

?

http://blog.csdn.net/qfs_v/archive/2008/05/07/2410308.aspx

?

怎么使用? REF游标 ?
?①声明REF 游标类型,确定REF 游标类型;
??⑴强类型REF游标:指定retrun type,REF 游标变量的类型必须和return type一致。
???语法:Type?? REF游标名?? IS?? Ref Cursor Return? 结果集返回记录类型;
??⑵弱类型REF游标:不指定return type,能和任何类型的CURSOR变量匹配,用于获取任何结果集。
???语法:Type?? REF游标名?? IS?? Ref Cursor;

?②声明Ref 游标类型变量;
??语法:变量名? 已声明Ref 游标类型;
??
?③打开REF游标,关联结果集 ;
??语法:Open?? Ref 游标类型变量?? For?? 查询语句返回结果集;
??
?④获取记录,操作记录;
??语法:Fatch??? REF游标名 InTo?? 临时记录类型变量或属性类型变量列表;
??
?⑤关闭游标,完全释放资源;
??语法:Close?? REF游标名;
?
?例子:强类型REF游标
?/*conn scott/tiger*/
?Declare
??Type MyRefCurA IS? REF CURSOR RETURN emp%RowType;
??Type MyRefCurB IS? REF CURSOR RETURN emp.ename%Type;
??vRefCurA? MyRefCurA;
??vRefCurB? MyRefCurB;
??vTempA? vRefCurA%RowType;
??vTempB? vRefCurB.ename%Type;
??
?Begin
??Open? vRefCurA? For Select? *? from?? emp?? Where? SAL > 2000;
??Loop
???Fatch? vRefCurA InTo? vTempA;
???Exit? When? vRefCurA%NotFound;
???DBMS_OUTPUT.PUT_LINE(vRefCurA%RowCount||'? '|| vTempA.eno||'? '||vTempA.ename ||'? '||vTempA.sal)
??End Loop;
??Close vRefCurA;
??
??DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------');
??
??Open? vRefCurB? For Select? ename? from?? emp?? Where? SAL > 2000;
??Loop
???Fatch? vRefCurB InTo? vTempB;
???Exit? When? vRefCurB%NotFound;
???DBMS_OUTPUT.PUT_LINE(vRefCurB%RowCount||'? '||vTempB)
??End Loop;
??Close vRefCurB;?
??
??DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------');???
??
??Open? vRefCurA? For Select? *? from?? emp?? Where? JOB = 'CLERK';
??Loop
???Fatch? vRefCurA InTo? vTempA;
???Exit? When? vRefCurA%NotFound;
???DBMS_OUTPUT.PUT_LINE(vRefCurA%RowCount||'? '|| vTempA.eno||'? '||vTempA.ename