1,什么是 REF游标 ?
 动态关联结果集的临时对象。即在运行的时候动态决定执行查询。
 
2,REF 游标 有什么作用?
 实现在程序间传递结果集的功能,利用REF CURSOR也可以实现BULK SQL,从而提高SQL性能。

 

3,静态游标和REF 游标的区别是什么?
 ①静态游标是静态定义,REF 游标是动态关联;
 ②使用REF 游标需REF 游标变量。
 ③REF 游标能做为参数进行传递,而静态游标是不可能的。
 
4,什么是REF 游标变量?
 REF游标变量是一种 引用 REF游标类型  的变量,指向动态关联的结果集。

 

5,怎么使用  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;

6,怎样让REF游标作为参数传递?

--作为函数返回值
create or replace function returnacursor return sys_refcursor 
is
   v_csr sys_refcursor;
begin
    open v_csr for select a1 from test3;
    return v_csr;
end;
/
declare
c sys_refcursor;
a1 char(2);
begin
  c:=returnacursor;
  loop
    fetch c into a1;
    exit when c%notfound;
    dbms_output.put_line(a1);
  end loop;
  close c;
end;
/
 
--作为参数
create or replace procedure proc_ref_cursor (rc in sys_refcursor) as
  v_a number;
  v_b varchar2(10);
  
begin
  loop
    fetch rc into v_a, v_b;
    exit when rc%notfound;
    dbms_output.put_line(v_a || ' ' || v_b);
  end loop;
end;
/
declare
v_rc sys_refcursor;
begin
  open v_rc for 
  select a1,a2 from test3;
  proc_ref_cursor(v_rc);
  close v_rc;
end;
/

创建 Oracle 包和包正文
这些示例要求服务器上存在以下 PL/SQL 包和包正文。在 Oracle 服务器上创建以下 Oracle 包

CREATE OR REPLACE PACKAGE BODY CURSPKG AS
    PROCEDURE OPEN_ONE_CURSOR (N_EMPNO IN NUMBER,
                               IO_CURSOR IN OUT T_CURSOR)
    IS 
        V_CURSOR T_CURSOR; 
    BEGIN 
        IF N_EMPNO <> 0 
        THEN
             OPEN V_CURSOR FOR 
             SELECT EMP.EMPNO, EMP.ENAME, DEPT.DEPTNO, DEPT.DNAME 
                  FROM EMP, DEPT 
                  WHERE EMP.DEPTNO = DEPT.DEPTNO 
                  AND EMP.EMPNO = N_EMPNO;
        ELSE 
             OPEN V_CURSOR FOR 
             SELECT EMP.EMPNO, EMP.ENAME, DEPT.DEPTNO, DEPT.DNAME 
                  FROM EMP, DEPT 
                  WHERE EMP.DEPTNO = DEPT.DEPTNO;
        END IF;
        IO_CURSOR := V_CURSOR; 
    END OPEN_ONE_CURSOR;
    PROCEDURE OPEN_TWO_CURSORS (EMPCURSOR OUT T_CURSOR,
                                DEPTCURSOR OUT T_CURSOR)
    IS 
        V_CURSOR1 T_CURSOR; 
        V_CURSOR2 T_CURSOR; 
    BEGIN 
        OPEN V_CURSOR1 FOR SELECT * FROM EMP;
        OPEN V_CURSOR2 FOR SELECT * FROM DEPT;
        EMPCURSOR  := V_CURSOR1; 
        DEPTCURSOR := V_CURSOR2; 
    END OPEN_TWO_CURSORS; 
END CURSPKG;
/

怎样让REF游标作为参数传递?

1)存储过程

CREATE OR REPLACE PROCEDURE findset_emp(v_deptno IN NUMBER,
                                        c_cursor OUT SYS_REFCURSOR) AS
BEGIN
    OPEN c_cursor FOR
        SELECT *
        FROM emp
        WHERE deptno = v_deptno;
END;

2)Java调用

public static void main(String[] args) {
        // TODO Auto-generated method stub
        try{
            // load oracle driver
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl","scott","tiger");
                                    
            CallableStatement cs = ct.prepareCall("{call findset_emp(?,?)}");
            cs.setInt(1, 10);
            cs.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);
            
            cs.execute();
            ResultSet rs = (ResultSet)cs.getObject(2);
            while(rs.next()){
                System.out.println(rs.getInt(1)+" "+rs.getString(2));
            }
            cs.close();
            ct.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }

 

posted on 2016-01-29 12:00  殷逸晨  阅读(223)  评论(0)    收藏  举报