2015년 9월 3일 목요일

오라클 명시적 커서(Explicit Cursor)

오라클 명시적 커서(Explicit Cursor)

 멀티 로우를  SELECT 하기위해 사용한다.
 선언(Declaring) : Declare 섹션에서 정의한다. 메모리 초기화 단계이며 커서에 이름을 부여하고 SELECT문장을 정의하며, SELECT문에는 INTO 절이 필요없다.
CURSOR c_emp IS SELECT * FROM emp;
 오픈(Opening) : SQL문장을 실행하고 커서를 위한 메모리를 할당하며 BEGIN 절에서 실행한다. 커서는 SELECT된 데이터(Active Set)의 첫번째 레코드에 포인터가 위치하고 패치단계에서 사용할 수 있게 된다. OPEN시 실행되는 SQL문장에서 추출되는 레코드가 없더라도 오류가 발생하지 않고 데이터가 없다는 것은 이후 FETCH를 마친 후 커서 속성값을 통해 판단 할 수 있다.(%FOUND)
OPEN c_emp;
 패치(Fetching) : 데이터 추출단계이며 FETCH되는 레코드가 없더라도 오류가 발생하지 않는다. INTO절 다음에 오는 칼럼 리스트는 SELECT시 정의한 칼럼 리스트와 개수, 타입이 동일해야 한다. “SELECT *” 등으로 커서를 만들었다면 %ROWTYPE을 적절히 이용하면 된다.
FETCH c_emp INTO c_emp_record;
 종료(Closing) : 커서 Closing
CLOSE c_emp;

[명시적 커서의 속성]
커서이름%ISOPEN : 커서가 오픈되었으면 TRUE
커서이름%FOUND : FETCH했는데 레코드가 있었으면 TRUE
커서이름%NOTFOUND : FETCH했는데 레코드가 없었으면 TRUE
커서이름%ROWCOUNT : 지금까지 FETCH한 데이터 건수

%FOUND %ISOPEN %NOT FOUND %ROWCOUNT
OPEN 전 오류 FALSE 오류 오류
  후 NULL TRUE NULL 0
First FETCH 전 NULL TRUE NULL 0
  후 TRUE TRUE FALSE 1
Next FETCH(es) 전 TRUE TRUE FALSE 1
  후 TRUE TRUE FALSE 패치한 건수
Last FETCH 전 TRUE TRUE FALSE 패치한 건수
  후 FALSE TRUE TRUE 패치한 건수
CLOSE 전 FALSE TRUE TRUE 패치한 건수
  후 오류 FALSE 오류 오류

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
      CURSOR c_emp IS
      SELECT ename, sal FROM emp WHERE deptno = 10;
      v_ename emp.ename%TYPE;
      v_sal  emp.sal%TYPE;
    BEGIN
      OPEN c_emp;
      LOOP
          FETCH c_emp INTO v_ename, v_sal;
        EXIT WHEN c_emp%NOTFOUND OR c_emp%NOTFOUND IS NULL;
        DBMS_OUTPUT.PUT_LINE(c_emp%ROWCOUNT || '. ' || v_ename || ',' || v_sal);
      END LOOP;
      CLOSE c_emp;
  END;
  /

1. CLARK,2837
2. KING,5789
3. MILLER,1505

-- CURSOR FOR LOOP는 커서의 레코드를 알아서 다 처리해주므로 EXIT WHEN이 필요없다
-- 알아서 OPEN하고 알아서 FETCH, Closing 한다. 즉 선언만 하여 사용하면 된다.
SQL> DECLARE
      CURSOR c_emp IS
      SELECT ename, sal FROM emp WHERE deptno = 10;
    BEGIN
      FOR emp_record IN c_emp LOOP
          DBMS_OUTPUT.PUT_LINE(c_emp%ROWCOUNT || '. '
              || emp_record.ename || ',' || emp_record.sal);
      END LOOP;
    END;
  /

1. CLARK,2837
2. KING,5789
3. MILLER,1505

-- 아래와 같이 커서 정의를 CURSOR FOR LOOP헤더에서 해도 된다.
-- 물론 커서이름이 없으니 커서의 속성은 사용하지 못한다.
SQL> DECLARE
    BEGIN
      FOR emp_record IN (SELECT ename, sal FROM emp WHERE deptno = 10) LOOP
          DBMS_OUTPUT.PUT_LINE(emp_record.ename || ',' || emp_record.sal);
      END LOOP;
    END;
  /

CLARK,2837
KING,5789
MILLER,1505

댓글 없음:

댓글 쓰기