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.youkuaiyun.com/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 ||' '||vTempA.sal)
End Loop;
Close vRefCurA;
End;
例子:弱类型REF游标
/*conn scott/tiger*/
Declare
Type MyRefCur IS Ref Cursor;
vRefCur MyRefCur;
vtemp vRefCur%RowType;
Begin
Case(&n)
When 1 Then Open vRefCur For Select * from emp;
When 2 Then Open vRefCur For Select * from dept;
Else
Open vRefCur For Select eno, ename from emp Where JOB = 'CLERK';
End Case;
Close vRefCur;
End;