2015년 8월 27일 목요일

DBMS_SQL 패키지를 이용한 REF CURSOR(참조커서)

DBMS_SQL 패키지를 이용한 REF CURSOR(참조커서)

 ORACLE 11g이후 DBMS_SQL과 Native Dynamic SQL은 2개의 새로운 API를 통해 REF CURSOR와 DBMS_SQL의 CURSOR를 서로 변경할 수 있도록 있다.

DBMS_SQL.TO_REFCURSOR

 DBMS_SQL을 이용하여 만든 커서를 참조커서(REF CURSOR)로 변환한다.

-- 아래 예제는 EMP 테이블에서 입력한 부서코드의 사원을 출력하는 예제이다.
SQL> SET SERVEROUTPUT ON
SQL> ACCEPT p_deptno PROMPT 'Enter the Deptno:'
SQL> DECLARE
          -- 테이블타입은 데이터를 배열처럼 다룰 수 있는 타입인데
          -- 배열첨자를 위해 4바이트 정수형 PLS_INTEGER를 사용했다.
          TYPE emp_record IS TABLE OF emp%ROWTYPE
          INDEX BY PLS_INTEGER;
          v_emps    emp_record;
          v_sql    CLOB;
          v_cursor  PLS_INTEGER;
          v_rc      SYS_REFCURSOR;  --REF CURSOR형
          v_execute PLS_INTEGER;
      BEGIN
        v_cursor := DBMS_SQL.OPEN_CURSOR;
        v_sql := 'SELECT * FROM emp WHERE deptno = :deptno';
 
        -- Dynamic SQL문 파싱
        DBMS_SQL.PARSE(v_cursor, v_sql, DBMS_SQL.NATIVE);
 
        -- 바인드변수 바인딩
        DBMS_SQL.BIND_VARIABLE(v_cursor, 'DEPTNO', '&p_deptno');
 
        -- SQL문 실행
        v_execute := DBMS_SQL.EXECUTE(v_cursor);
 
        -- REF CURSOR로 변환
        v_rc := DBMS_SQL.TO_REFCURSOR(v_cursor);
 
        -- REF CURSOR에서 데이터 추출
        LOOP
            FETCH v_rc BULK COLLECT INTO v_emps LIMIT 100;
            FOR i IN 1 .. v_emps.COUNT LOOP
              DBMS_OUTPUT.PUT_LINE(v_emps(i).ename || v_emps(i).sal);
            END LOOP;
            EXIT WHEN v_rc%NOTFOUND;
        END LOOP;
        CLOSE v_rc;
      END;
    /
'Enter the Deptno:: 20

구  19:      DBMS_SQL.BIND_VARIABLE(v_cursor, 'DEPTNO', '&deptno');
신  19:      DBMS_SQL.BIND_VARIABLE(v_cursor, 'DEPTNO', '20');
SMITH800
……
FORD3000

-- 이번에는 REF CURSOR를 리턴해 보자.
-- 아래처럼 함수의 리턴타입을 SYS_REFCURSOR로 하면 컴파일은 되지만 클라이언트쪽에서 출력되지 않는다.(Oracle 11g Release2 이후에는 가능하다)

SQL> CREATE OR REPLACE FUNCTION emplist (p_deptno emp.deptno%TYPE)
  2      RETURN SYS_REFCURSOR
  3  IS
  4        v_sql    CLOB;
  5        v_cursor  PLS_INTEGER;
  6        v_rc      SYS_REFCURSOR;  --REF CURSOR형
  7        v_execute PLS_INTEGER;
  8    BEGIN
  9        v_cursor := DBMS_SQL.OPEN_CURSOR;
 10      v_sql :='SELECT * FROM emp WHERE deptno = :deptno';
 11
 12        -- Dynamic SQL문 파싱
 13        DBMS_SQL.PARSE(v_cursor, v_sql, DBMS_SQL.NATIVE);
 14
 15        -- 바인드변수 바인딩
 16        DBMS_SQL.BIND_VARIABLE(v_cursor, 'DEPTNO', p_deptno);
 17
 18        -- SQL문 실행
 19        v_execute := DBMS_SQL.EXECUTE(v_cursor);
 20
 21        -- REF CURSOR로 변환
 22        v_rc := DBMS_SQL.TO_REFCURSOR(v_cursor);
 23
 24        return v_rc;
 25    END;
 26    /

함수가 생성되었습니다.

SQL> set autoprint on
SQL> variable refcur REFCURSOR
SQL> BEGIN
  2      :refcur := emplist(10);
  3  END;
  4  /
BEGIN
*
1행에 오류:
ORA-03001: 현재에는 구현되어 있지 않은 기능입니다
ORA-06512: "SYS.DBMS_SQL",  1104행
ORA-06512: "SCOTT.EMPLIST",  13행
ORA-06512:  2행

ERROR:
ORA-24338: 문장 처리가 수행되지 않았습니다

-- 출력이 되도록 하고 싶으면 이전에 작성한 형태대로 별도의 패키지등에서 REF CURSOR 타입을 미리 정의하면 된다.
SQL> create or replace package types
as
type curtype is ref cursor;
end;
/

SQL> CREATE OR REPLACE FUNCTION emplist (p_deptno emp.deptno%TYPE)
    RETURN TYPES.CURTYPE
IS         
      v_sql    CLOB;
      v_cursor  PLS_INTEGER;
      v_rc      TYPES.CURTYPE;  --REF CURSOR형
      v_execute PLS_INTEGER;
  BEGIN 
      v_cursor := DBMS_SQL.OPEN_CURSOR;     
    v_sql :='SELECT *  FROM emp WHERE deptno = :deptno';
 
      -- Dynamic SQL문 파싱
      DBMS_SQL.PARSE(v_cursor, v_sql, DBMS_SQL.NATIVE);
 
      -- 바인드변수 바인딩
      DBMS_SQL.BIND_VARIABLE(v_cursor, 'DEPTNO', p_deptno);
 
      -- SQL문 실행
      v_execute := DBMS_SQL.EXECUTE(v_cursor);
     
      -- REF CURSOR로 변환
      v_rc := DBMS_SQL.TO_REFCURSOR(v_cursor);
     
      return v_rc;
  END;
/

SQL> set autoprint on
SQL> variable refcur REFCURSOR
SQL> BEGIN
  2      :refcur := emplist(10);
  3  END;
  4  /

    EMPNO ENAME      JOB          MGR  HIREDATE    SAL      COMM    DEPTNO
    -----------------------------------------------------------------------------------------------------
      7782  CLARK      MANAGER    7839    81/06/09    3404.4              10
      7839  KING      PRESIDENT            81/11/17    6946.8              10
      7934  MILLER    CLERK        7782    82/01/23    2257.5              10 

댓글 없음:

댓글 쓰기