오라클/PL/SQL

PL/SQL CURSOR

김포춘 2014. 10. 14. 14:00
반응형

커서 - 묵시적 커서(Implicit Cusor) : 필요할 경우 오라클이 자동적으로 선언하여 사용한 후 자동적으로 정리

 - 명시적 커서(Explicit Cursor) : 사용자가 정의한 커서른 선언하여 사용하고, 커서의 사용이 끝난 후에는 별도의 정리                                                작업을 수행해줘야 함



묵시적 커서

- 세션 내에 단 한 개만이 선언되어 사용되었다가 문장이 종료됨과 동시에 정리, 1개의 데이터만 저장됨


묵시적 커서 속성

- SQL%ROWCOUNT

해당 커서에서 실행한 총 행의 개수(가장 마지막 행이 몇 번째 행인지 카운트)를 반환


- SQL%FOUND

해당 커서 안에 아직 수행해야 할 데이터가 있을 경우 TRUE 값을 반환하고 없을경우 FALSE 값을 반환


- SQL%NOTFOUND

해당 커서 안에 아직 수행해야 할 데이터가 없을 경우 TRUE 값을 반환하고 있을경우 FALSE 값을 반환


- SQL%ISOPEN

현재 묵시적 커서가 메모리에 OPEN 되어 있을 경우에는 TRUE 값을, 그렇지 않을 경우 FALSE 값을 가지는 속성


사용 예)


SCOTT>DECLARE

BEGIN

DELETE emp

WHERE sal < 1000 ;

DBMS_OUTPUT.PUT_LINE('1000 이하 : '||sql%rowcount||'건 삭제되었습니다') ;

DELETE emp

WHERE sal BETWEEN 1000 AND 2000 ;

DBMS_OUTPUT.PUT_LINE('1000~2000 사이 : '||sql%rowcount||'건 삭제 되었습니다') ;

END ;

/


-> 1000 이하 : 2 건 삭제 되었습니다

     1000 ~2000 사이 : 6 건 삭제 되었습니다


명시적 커서

사용자가 선언하여 생성 후 사용하는 SQL 커서로, 여러 개의 행을 처리하고자 할 경우 사용


명시적 커서 속성

- 커서이름%ROWCOUNT

FETCH 문에 의해 읽혀진 데이터의 총 행 수를 가지는 속성. 가장 마지막에 처리된 행이 몇 번째 인지 반환

- 커서이름%FOUND

FETCH 문이 수행되었을 경우, 읽혀진(FETCH) 행이 있을 경우에는 TRUE 값을, 그렇지 않을 경우 FALSE 값을 가짐

- 커서이름%NOTFOUND

FETCH 문이 수행되었을 경우, 읽혀진(FETCH) 행이 없을 경우에는 TRUE 값을, 그렇지 않을 경우 FALSE 값을 가짐

- 커서이름%ISOPEN

명시적 커서가 메모리에 확보(선언) 되어 있을 경우에는 TRUE 값을, 그렇지 않을 경우에는 FALSE 값을 가짐


묵시적 커서와 FOR LOOP 문 활용하기

      

SCOTT>DECLARE

BEGIN

DBMS_OUTPUT.PUT_LINE('학과명과 학과의 위치 안내 입니다') ;

DBMS_OUTPUT.PUT_LINE('---------------------------------') ;

FOR dept_cur IN (SELECT dname,build

                                     FROM department 

                   WHERE build IS NOT NULL

 ORDER BY 1)

LOOP

DBMS_OUTPUT.PUT_LINE(dept_cur.dname||'-->'||dept_cur.build||'에 있습니다') ;

END LOOP ;

END ;

/


-> 학과명과 학과의 위치 안내 입니다

-------------------------------------

기계공학과 --> 기계실험관 에 있습니다

멀티미디어공학과 --> 멀티미디어관 에 있습니다

문헌정보학과 --> 인문관 에 있습니다

.... 


명시적 커서 처리 단계

1) 명시적 커서 선언 (Declaration)

PL/SQL의 선언부(DECLARE)에 다른 변수와 마찬가지로 선언되어야 하며, 형식은 아래와 같다

- 문법 :

CURSOR 커서명 IS 커서에 담고 싶은 내용을 가져오는 서브쿼리

- 커서명 : 명시적 커서의 이름

- 서브쿼리 : 처리하고자 하는 데이터를 검색하는 SELECT 문장을 이부분에 기술


2) 명시적 커서 오픈(OPEN)

선언 시 기술했던 서브쿼리를 수행해서 데이터를 커서로 가져 온다는 뜻. 

- 문법 :

OPEN 커서 이름 ;

- 커서이름 : 열고자 하는 명시적 커서의 이름


3) 명시적 커서로부터 데이터 읽어서 변수로 할당하기(FETCH)

명시적 커서의 데이터들로부터 데이터를 한 건씩 읽어 변수로 할당하기 위해 FETCH문을 사용

- 문법 :

FETCH 커서 이름 INTO 변수

- 커서이름 : 읽어(FETCH) 오고자 하는 명시적 커서의 이름으로 반드시 OPEN 되어 있어야 FETCH 가능

- 변수들 : 명시적 커서로부터 읽어온(FETCH) 데이터 행(레코드) 을 PL/SQL 블록 내에서 처리하기 위해서   

               변수에 저장해서 사용. 


4) 명시적 커서 닫기(CLOSE)

명시적 커서의 정리 작업을 하는 명령으로, 명시적 커서가 다 사용된 후에는 반드시 '닫기'를 해야 함.

커서를 닫는다 함은 작업이 끝난 메모리 공간을 반환하고 정리한다는 뜻

- 문법 :

CLOSE 커서 이름 ;

- 커서이름 : 닫고자 하는 명시적 커서의 이름으로 Close 된 명시적 커서는 더 이상 사용하지 않는다


사용 예)

SCOTT>DECLARE

vempno NUMBER(4) ;

vename VARCHAR2(20) ;

vsal NUMBER(7) ;


     (커서 선언)     CURSOR c1 IS

      SELECT empno, ename, sal

            FROM emp

      WHERE deptno=20 ;

           

BEGIN

     (커서 오픈)    OPEN c1 ;

            DBMS_OUTPUT.PUT_LINE('번호 이름  급여') ;

          

LOOP

    (데이터 추출)  FETCH c1 INTO vempno, vename, vsal ;

            EXIT WHEN c1%NOTFOUND ;

         

DBMS_OUTPUT.PUT_LINE(vempno||'  '||vename||' '||vsal) ;

            END LOOP ;

     (커서 닫기)    CLOSE c1 ;

      END ;

/



명시적 커서와 Cursor FOR LOOP 문 활용

문법 :

FOR record_name IN cursor_name LOOP

-- 명시적 커서의 OPEN, FETCH 가 자동적으로 수행됨.

statement1 ;

statement2 ;

....

END LOOP ; -- 루프문을 빠져 나갈 때 자동적으로 커서가 CLOSE 됨.


- record_name 커서로부터 FETCH 된 하나의 레코드를 저장하기 위한 커서 레코드 변수, 자동으로 만들어짐

- cursor_name : 처리하고자 하는 명시적 커서명으로, 선언부에서 정의되어야 함. 


명시적 CURSOR 와 CURSOR FOR LOOP 문 사용 예 :

emp 테이블에서 empno, ename 값을 가져와서 커서에 저장 후 출력하세요.


SCOTT>DECLARE

 CURSOR emp_cur IS   -- 커서 선언

       SELECT empno, ename

       FROM emp ;

    BEGIN

       FOR emp_rec IN emp_cur      -- 커서의 데이터를 저장할 emp_rec 변수 선언

        LOOP

          DBMS_OUTPUT.PUT_LINE(emp_rec.empno||' '||emp_rec.ename) ;

        END LOOP ;

    END ;

  /


파라미터 Explicit Cursor

- 명시적 커서를 선언 한 후 OPEN 할 때 값을 바꾸어서 수행해야 할 경우, 커서를 OPEN 할 때 필요한 값만 파라미터로 

전달해서 반복 수행 할 수 있는 방법

문법 :

CURSOR cursor_name

[(parameter_name dataTYPE ,...)] 

IS select-statement ;


- parameter_name : 파라미터 변수명으로 변수선언과 동일하며 여러 개의 파라미터를 지정할 수 있다


파라미터 Explicit Cursor 사용 예 :

SCOTT>DECLARE

CURSOR prof_cur (v_deptno IN NUMBER)

IS SELECT *

FROM professor

WHERE deptno=v_deptno ;

v_prof professor%ROWTYPE ;

BEGIN

DBMS_OUTPUT.PUT_LINE('============================') ;

DBMS_OUTPUT.PUT_LINE('101번 학과 교수님 번호와 이름 출력') ;

DBMS_OUTPUT.PUT_LINE('----------------------------') ;

OPEN prof_cur(101) ;

LOOP

FETCH prof_cur INTO v_prof ;

EXIT WHEN prof_cur%NOTFOUND ;

DBMS_OUTPUT.PUT_LINE(v_prof.profno||' 번 교수님 이름은 '||v_prof.name||' 입니다') ;

END LOOP ;

CLOSE prof_cur ;

DBMS_OUTPUT.PUT_LINE('============================') ;

DBMS_OUTPUT.PUT_LINE('102번 학과 교수님 번호와 이름 출력') ;

DBMS_OUTPUT.PUT_LINE('----------------------------') ;

OPEN prof_cur(102) ;

LOOP   

FETCH prof_cur INTO v_prof ;

EXIT WHEN prof_cur%NOTFOUND ;

DBMS_OUTPUT.PUT_LINE(v_prof.profno||' 번 교수님 이름은 '||v_prof.name||' 입니다') ;

END LOOP ;

CLOSE prof_cur ;

END ;

/


Cursor 와 Select....FOR UPDATE 문장

명시적 커서를 선언해 데이터를 조회한 후 변경을 하려는 중에 다른 세션에서 현 세션이 작업하는 내용을 변경 할 수 있다.

예를 들어 조회 할 시점에 A라는 데이터였지만 조회나 변경하는 중에 다른 세션이 B 라는 데이터로 바꿀수 있다는 뜻

그래서 커서를 선언 할 때 커서에 있는 행들에 대해 잠금을 수행.


1) 기본 문법 

이 실습을 위해 두 개의 세션에서 작업 실행


-세션 1-                                                                    -세션 2-

SCOTT>SELECT empno,ename,sal                                SCOTT>UPDATE emp

FROM emp                                                                  SET sal = 1000

WHERE empno = 7900                                                  WHERE empno = 7900 ;

FOR update ;                                                    -> 대기 상태로 반응 없습니다.


EMPNO    ENAME    SAL

------   -------   ----

    7900     JAMES    950

위와 같이 세션 1 에서 select 구문에 for update를 함께 쓰면 해당 데이터에 lock이 설정되어 다른 세션에서 dml 작업을 할 경우 대기상태로 들어감.

이 상태에서 세션 1 에서 commit 이나 rollback 명령을 수행하면 세션 2 에서 작업이 진행됨


2) Cursor 에서 SELECT... FOR update 사용하기

문법 :

SELECT ...

FROM ...

FOR UPDATE [OF column_reference][NOWAIT|WAIT n] ;


위 옵션중 NOWAIT 옵션은 다른 세션에서 행을 잠글 경우 즉시 오라클 에러를 발생 시켜주는 옵션.

다른 세션에서 해당 행에 LOCK 을 설정했을 경우 NOWAIT 옵션을 사용하면 즉시 에러를 발생시킴

그러나 만약 NOWAIT 옵션을 사용하지 않을 경우 LOCK 이 확보 될 때 까지 무한 대기상태

WAIT n = n자리에 초를 설정할 수 있으며 해당 초가 지난 후에도 LOCK을 확보할 수 없으며 에러발생


Cursor 에서 FOR UPDATE 구문 사용 예 :

DECLARE

CURSOR emp_cur IS

SELECT empno, ename, sal

FROM emp

WHERE deptno = 20

FOR UPDATE     -- 커서 선언시에 FOR UPDATE 로 행을 잠금

NO WAIT ;

....

BEGIN

....

OPEN emp_cur ;

....

UPDATE emp

SET sal = sal * 2

WHERE CURRENT OF emp_cur          -- 커서 선언 시에 잠긴 행 갱신

....

CLOSE emp_cur ;

END ;


반응형

'오라클 > PL/SQL' 카테고리의 다른 글

PL/SQL sub program  (0) 2014.10.16
PL/SQL 예외처리  (0) 2014.10.16
PL/SQL 제어문  (0) 2014.10.13
PL/SQL 변수  (0) 2014.10.13
PL/SQL 시작하기  (0) 2014.10.13