4. PL/SQL Cursor(커서) 정리해야됨.
[기타SQL]/PL_SQL 2014. 10. 14. 12:23 |4장. PL/SQL Cursor(커서)
1.SQL커서란 ?
: Context Area(sql문 실행할 때마다 처리하기 위해 SGA내부에서 사용하는 개별적인 메모리 공간)에 있는 데이터를 사람이 접근 할 수 있도록 연결해주는 일종의 연결통로.(포인터라고도 부른다.)
즉, 사용자가 요청하는 데이터를 데이터베이스 버퍼 캐쉬에서 PL/SQL 이 사용하는 개별적인 메모리공간으로 복사 해 온 후(복사 한 데이터 : Active Set),
-> 커서를 통해서 Context Area 있는 Active Set 중에서 원하는 데이터에 접근한 후 필요한 데이터를 추출하여(FETCH),
-> PL/SQL 변수에 담고 후속 작업을 하게 된다는 뜻이다.
오라클의 서버 프로세스 구성이 Dedicated Server 환경이냐 또는 MTS(Multi-Threaded Server)환경이냐에 따라 서버 내에 위치되는 곳이 다르다.
- Context Area : PL/SQL을 사용하여 작업을 할 경우 오라클이 항상 해당 세션에게 SGA 내부에 해당세션만 사용할 수 있도록 개별(Private)로 할당하는 공간..
- Context Area 에는 SQL Query 와 해당 SQL문장의 파싱 관련 정보들과 결과(data set)가 모두 들어있다.
- 사용자가 PL/SQL 을 통해서 특정 SQL ( SELECT나 DML ) 을 처리하고자 할 경우 일단 Database Buffer Cache에서 원하는 데이터를 뽑아서 Context Area 로 데이터를 가져 온 후 PL/SQL 변수에 담아서 후속 작업을 진행한다.
- 이때 가져오는 데이터가 1 건일 경우에는 Context Area 에 오라클이 자동으로 묵시적 커서를 생성해서 사용하고
만약 여러 건을 가져와야 할 경우 사용자가 명시적 커서를 미리 생성해야 한다.
- Cursor 는 실제 테이블을 가리키는 포인터가 아니라 , 결과셋 값을 가리키는 포인터 정보이다.
사용자가 T1 , T2 , T3 테이블을 조인을 하는 커서를 만들고 그 결과를 PL/SQL 변수에 담을 경우에
커서가 OPEN 이 되면 DB Buffer Cache 에서 필요한 컬럼만 빼서 Cursor Area 에 가져다 놓는다.
그리고 커서를 통해서 Cursor Area 에 있는 데이터의 위치를 찾아가서 데이터를 꺼내와서 (FETCH 단계)PL/SQL 변수에 담는다.
PL/SQL 커서는 크게 묵시적 커서(Implicit Cursor)와 명시적 커서(Explicit Cursor)로 나눌 수 있다.
묵시적 커서는 필요할 경우 오라클이 자동적으로 선언하여 사용한 후 자동적으로 정리(Clean-up) 한다.
PL/SQL 블록이 실행될 때 내부에 포함된 SQL 문장에 대해 SQL 커서가 자동적으로 생성된다. 즉 사용자가 생성을 하지 않아도 자동으로 생성된다.
2. 묵시적 커서(Implicit Cursor)
묵시적 커서는 오라클에서 자동적으로 선언해주는 SQL 커서로서, 사용자 입장에서는 생성 유무를 알 수 없다.
기본적으로 PL/SQL 블록 내에서의 SELECT문, DML(INSERT, UPDATE, DELETE) 문이 실행될 때마다 묵시적 커서가 선언된다.
주의해야 할 점은 묵시적 커서의 경우 세션 내에 단 한 개만이 선언되어 사용되었다가 문장이 종료됨과 동시에 정리된다.
그리고 묵시적 커서에 저장되는 데이터는 1 행만 가능하여, 여러 행을 저장해서 작업 해야 할 경우에는 묵시적 커서를 사용할 수 없다.
* 묵시적 커서 속성(Cursor Attribute) (별로안중요)
SQL%ROWCOUNT |
해당 커서에서 실행한 총 행의 개수(가장 마지막 행이 몇 번째 행인지 카운트합니다)를 반환. |
SQL%FOUND |
해당 커서 안에 아직 수행해야 할 데이터가 있을 경우 TRUE 값을 반환하고, 없을 경우FALSE값을 반환하는 속성. |
SQL%NOTFOUND |
해당 커서 안에 수행해야 할 데이터가 없을 경우 TRUE값을 반환하고 있을 경우 FALSE값을 반환하는 속성 |
SQL%ISOPEN |
현재 묵시적 커서가 메모리에 OPEN 되어 있을 경우 TRUE값을, 그렇지 않을 경우에는 FALSE값을 가지는 속성 |
* 묵시적 커서 사용 예:
- emp table 에서 sal 을 조회한 화면.
14 rows selected.
|
- 묵시적 커서를 활용해서 emp table 에서 sal 이 100이하인 경우와 1000 - 2000 사이인 경우를 지우고 각 몇 건이 지워졌는지 화면에 출력.
SCOTT>DECLARE
PL/SQL procedure successfully completed.
|
3. 명시적 커서(Explicit Cursor)
명시적 커서는 사용자가 선언하여 생성 후 사용하는 SQL 커서로, 주로 여러 개의 행을 처리하고자 할 경우 사용.
(만약 여러건을 검색하는 SELECT문장의 경우 묵시적 커서를 사용할 경우 오라클은 예외사항(TOO_MANY_ROWS)을 발생한다.)
명시적 커서는 여러 개가 선언될 수 있으므로, 커서 속성 변수는 ‘커서명(Cursor Name)%’을 커서 속성 변수의 접두어(Prefix)로 붙여서 사용한다.
(묵시적 커서는 커서가 하나밖에 없었기 때문에 접두어로 SQL 을 사용)
* 명시적 커서 속성(Cursor Attribute)
커서이름%ROWCOUNT |
FETCH 문에 의해 읽혀진 데이터의 총 행 수. 가장 마지막에 처리된 행이 몇 번째 인지를 반환. |
커서이름%FOUND |
FETCH 문이 수행되었을 경우, 읽혀진(FETCH) 행이 있을 경우에는 TRUE값을, 그렇지 않을 경우에는 FALSE값을 가지는 속성 |
커서이름%NOTFOUND |
FETCH 문이 수행되었을 경우, 읽혀진(FETCH ) 행이 없을 경우에는 TRUE값을, 그렇지 않을 경우에는 FALSE값을 가지는 속성 |
커서이름%ISOPEN |
명시적 커서가 메모리에 확보(선언)되어 있을 경우에는 TRUE값을, 그렇지 않을 경우에는 FALSE(거짓) 값을 가지는 속성. |
* 묵시적 커서와 FOR LOOP 문 활용하기
SCOTT> DECLARE ================================================
|
4. 명시적 커서(Explicit Cursor) 처리 단계
1) 명시적 커서 선언(Declaration)
해당 커서를 사용 하겠다고 PL/SQL 에 알려주는 역할만 하며,실제 메모리 할당이 이루어지는 것은 아니다.
[문 법]
CURSOR 커서명
|
2) 명시적 커서 열기(OPEN )
커서 선언 시 기술했던 서브쿼리를 수행해서 데이터를 커서로 가져 온다. 이 때 메모리에 실제 커서가 사용할 메모리 공간이 할당이 된다.
명시적 커서 영역에 자리잡은 데이터의 첫 번째 행에 커서 포인터(pointer)가 설정되고 바로 이 포인터 위치의 데이터 행을 다음 단계인 FETCH에서 읽는다.
[문법]
OPEN 커서 이름 ;
|
3) 명시적 커서로부터 데이터 읽어서 변수로 할당하기(FETCH )
: 명시적 커서의 데이터들(Active Set)로부터 데이터를 한 건씩 읽어 변수로 할당.
이때 읽게 되는 데이터 행은 포인터(Pointer)에 의해서 지정되며 한 행이 FETCH 되면 자동적으로 포인터는 다음 행으로 이동한다.
일반적으로 명시적 커서에는 데이터가 여러 건 들어있기 때문에 많은 데이터들을 읽어 처리하기 위해서 FETCH 문은 반복문과 함께 사용하는 경우가 많다.
- FETCH 문도 FETCH 후에 변수에 값을 할당하기 위해 INTO 절을 사용한다.
[문 법]
FETCH 커서_이름 INTO 변수 |
- 커서_이름은 읽어오고자(FETCH) 하는 명시적 커서의 이름으로, 반드시 OPEN 되어 있어야 FETCH가 가능.
- 변수들:
명시적 커서로부터 읽어온(FETCH) 데이터 행(레코드)을 PL/SQL 블록 내에서 처리하기 위해서는
변수에 저장해서 사용합니다. 이때 variable 에는 단순변수와 복합변수가 올 수 있으며, 당연히 선언부에 선언된 변수만 올 수 있다.
만약 단순변수를 사용한다면, 커서에서 정의된 SELECT리스트의 개수만큼 선언하고, SELECT 리스트의 위치대로 FETCH의 INTO절에 차례대로 적어야 한다.
만약 복합변수를 사용한다면, 커서 레코드 변수(커서명%ROWTYPE )를 선언하여 사용한다.
4) 명시적 커서 닫기(Close) : 작업이 끝난 메모리 공간을 반환하고 정리.(명시적 커서의 정리(clean-up)작업을 하는 명령)
닫기를 하지 않게 되면 메모리 낭비도 많이 되고. 만약 동일한 커서를 다른 PL/SQL BLOCK 에서 동일한 이름의 커서를 사용할 경우 에러가 생긴다.
만약 사용자가 명시적 커서를 닫지 않고 다른 명시적 커서를 OPEN한다면 SGA 에 Cursor Work Area 에 메모리 공간 낭비가 심해진다.
[문 법]
CLOSE 커서_이름 ; |
- 명시적 커서 선언 및 사용 예 :
5. 명시적 커서와 Cursor FOR LOOP 문 활용하기
명시적 커서에는 일반적으로 여러 건의 데이터가 들어있으므로, 여러 번 FETCH 를 수행하게 되고 이를 위해 반복문을 사용한다.
그 중 가장 많이 사용되는 것이 FOR 문장인데 PL/SQL에서는 FOR 반복문과 커서를 결합하여 CURSOR FOR 반복 기능을 제공한다.
[문 법]
FOR record_name IN cursor_name LOOP -- 명시적 커서의 OPEN , FETCH 가 자동으로 수행됨.
|
- 명시적 CURSOR와 CURSOR FOR LOOP 문 사용 예:
emp 테이블에서 empno, ename 값을 가져와서 커서에 저장 후 출력. (커서 이름과 변수이름은 임의로 지정)
SCOTT>DECLARE 5 BEGIN |
6. 파라미터 Explicit Cursor
파라미터 커서란? : 명시적 커서를 선언 한 후 OPEN할 때 값을 바꾸어서 수행해야 할 경우가 종종 있는데,이때 커서를 OPEN 할 때 필요한 값만 파라미터로 전달해서 반복 수행 할 수 있는 방법이다.
[문 법]
CURSOR cursor_name |
- 파라미터 Explicit Cursor 사용 예 :
SCOTT> DECLARE
|
7. Cursor 와 SELECT.....FOR UPDATE 문장
명시적 커서를 선언해서 데이터를 조회한 후 변경을 하려는 중에 다른 세션에서 현 세션이 작업하는 내용을 변경 할 수 있는데, 이때 커서를 선언할 때 커서에 있는 행들에 대해 잠금(LOCK)을 수행할 수 있다.
- select문장의 가장 마지막 부분에 SELECT.... FOR UPDATE 문장을 사용하면 된다.
1) 기본 문법
[준비과정] : 두 개의 세션 준비.
- 세션 1 -
SCOTT>SELECT empno,ename,sal
|
- 세션 2 -
SCOTT>UPDATE emp 다른 세션에서 DML 작업을 할 경우 대기 상태로 들어갑니다
|
: 세션 1 에서 commit 이나 rollback 명령을 수행해서 transaction 을 종료하면 세션 2 에서도 작업이 진행이 계속 됩니다.
Q.세션1 에서 SELECT... FOR update 를 사용하려 할 때 이미 다른 세션에서 해당 데이터를 변경하고 있을 경우에는?
A. 이럴 경우 세션1에서는 대기상태로 자기 순서를 기다리게된다. 이런 경우를 대비해서 FOR update 에 두가지 옵션을 사용할 수 있다.
- FOR update nowait 옵션 : 만약 다른 사용자가 데이터를 먼저 변경하고 있을 경우 바로 에러를 발생하게 된다. 그리고 또 한가지는
- FOR udpate wait n 모드 : n 부분에 기다릴 시간을 지정해 주면 그 시간 동안 선행 작업이 끝날 때 까지 기다리다가, 그 시간내에 종료가 안되면 에러를 발생.
만약 시간을 지정 안하고 FOR update wait 만 사용할 경우 무한정 기다리게 되므로 꼭 숫자를 적어줘야 한다.
- 이렇게 Lock이 걸린 내역을 확인하려면 다른 터미널을 하나 더 열어서 관리자 계정으로 로그인 한 후조회하면 된다.
SYS> SELECT a.sid , a.serial# , b.TYPE , c.object_name 39 2415 AE ORA$BASE
|
- 위와 같이 SELECT... FOR update 는 Lock 을 설정하게 되어 다른 사용자의 Transaction 진행에 방해를 할 수 있으므로 사용에 아주 주의한다.
2) Cursor 에서 SELECT... FOR update 사용하기
[문 법]
SELECT...
|
- Cursor 에서 FOR UPDATE 구문 사용 예:
DECLARE
|
8. REF Cursor (현업에서 아주 많이 사용되고 있으나, 많이 어려우니 일단 건너뛰자.)
묵시적Cursor와 명시적Cursor는 Cursor가 선언이 될 때 수행 될 SQL을 미리 지정하고 실행하는 방법만을 지원한다.
예를 들어 사용자가 1 번을 선택하면 학생테이블을 조회하고, 2번을 선택하면 교수 테이블을 조회하고 3번을 선택하면 학과 테이블을 조회해서 결과를 출력해야 할 경우 3개의 Cursor를 만들어야 한다는 단점이 있다.
->묵시적 cursor와 명시적 cursor는 cursor가 선언될 때 sql이 지정되면, 이후 변경할 수 없으므로 정적(static)cursor라 한다.
Ref Cursor란 ? -> Ref Cursor 는 동적 (Dynamic) Cursor 라고 부른다. |
*Ref cursor 사용하기 위해 거치는 과정.
1) 선언부에서 Ref Cursor 이름을 선언한다. ( Sub Query 는 선언하지 않는다. )
2) RefCursor 를 사용할 변수를 선언한다. -> cursor가 open될 때 서브쿼리를 수행해서 그 결과를 임시로 담는 역할을 한다.
(이것은 앞에서 살펴본 Record TYPE 이나 Table TYPE을 선언하고 해당 TYPE 을 사용하는 변수를 추가로 선언해 준 방법과 동일. )
-> 만약 Strong Ref Cursor라면 Return TYPE 을 적어준다.
3)Cursor변수에 담긴 데이터를 옮겨 담을, 실제 변수를 선언한다. -> Cursor변수에 임시로 담겨 있는 데이터는 이 과정에서 만들어진 변수로 FETCH 된다.
(스칼라 변수도 괜찮고 만약 데이터가 여러 건일 경우는 앞에서 배운 Record TYPE 이나 Table TYPE 변수를 사용해도 된다.)
- Ref Cursor 는 다시 Weak Ref Cursor (약한 타입-비 제한적 타입)와 Strong Ref Cursor (강한 타입-제한적 타입)으로 나눌 수 있다.
Strong Ref Cursor 는 Cursor 를 수행 후에 반환되는 데이터타입을 명시적으로 지정해 주어야 한다.
반면 Weak Ref Cursor 는 반환되는 데이터타입을 지정하지 않아도 됩니다.
여기부터
1. Weak Ref Cursor (약한 타입- 비 제한적 Ref Cursor )
사용자에게 1) Student , 2) Professor , 3) Department 의 메시지를 보인 후에 사용자가 1 을 입력
하면 학생들의 학번(studno), 이름 (name) 을 출력하고 , 2를 입력하면 교수들의 교수번호(profno),
이름 (name)을 출력하고 , 3을 입력하면 학과의 번호(deptno), 학과명(dname) 을 출력하는 예입니
다.
SQL> @weak_ref1.sql <--- 실행합니다.
'출력을 원하는 번호를 선택하세요'
1) Student , 2) Professor , 3) Department : 1 <---- student table 선택합니다
Printing Student InFORmation---------
no: 9411 , name: 서진수
no: 9412 , name: 서재수
no: 9413 , name: 이미경
no: 9414 , name: 김재수
no: 9415 , name: 박동호
no: 9511 , name: 김신영
no: 9512 , name: 신은경
no: 9513 , name: 오나라
no: 9514 , name: 구유미
no: 9515 , name: 임세현
no: 9611 , name: 일지매
no: 9612 , name: 김진욱
no: 9613 , name: 안광훈
no: 9614 , name: 김문호
no: 9615 , name: 노정호
no: 9711 , name: 이윤나
no: 9712 , name: 안은수
no: 9713 , name: 인영민
no: 9714 , name: 김주현
no: 9715 , name: 허우
PL/SQL procedure successfully completed.
SQL> @weak_ref1.sql
'출력을 원하는 번호를 선택하세요'
1) Student , 2) Professor , 3) Department : 2 <--- professor 선택합니다
Printing Professor InFORmation---------
no: 1001 , name: 조인형
no: 1002 , name: 박승곤
no: 1003 , name: 송도권
no: 2001 , name: 양선희
no: 2002 , name: 김영조
no: 2003 , name: 주승재
no: 3001 , name: 김도형
no: 3002 , name: 나한열
no: 3003 , name: 김현정
no: 4001 , name: 심슨
no: 4002 , name: 최슬기
no: 4003 , name: 박원범
no: 4004 , name: 차범철
no: 4006 , name: 전민
no: 4007 , name: 허은
PL/SQL procedure successfully completed.
SQL> @weak_ref1.sql
'출력을 원하는 번호를 선택하세요'
1) Student , 2) Proffessor , 3) Department : 3 <- Department 선택합니다.
Printing Department InFORmation---------
no: 101 , name: 컴퓨터공학과
no: 102 , name: 멀티미디어공학과
no: 103 , name: 소프트웨어공학과
no: 201 , name: 전자공학과
no: 202 , name: 기계공학과
no: 203 , name: 화학공학과
no: 301 , name: 문헌정보학과
no: 100 , name: 컴퓨터정보학부
no: 200 , name: 메카트로닉스학부
no: 300 , name: 인문사회학부
no: 10 , name: 공과대학
no: 20 , name: 인문대학
PL/SQL procedure successfully completed.
================================================================
위와 같이 커서를 OPEN 하는 시점에 해당 작업을 할 SQL 이 지정되기 때문에 사용자가 입력한
값에 따라 다른 결과를 출력하게 됩니다.
2. Strong Ref Cursor (강한 타입- 제한적 Ref Cursor)
앞에서 살펴본 Weak Ref Cursor 은 Cursor 를 선언할 때 리턴 할 데이터 타입을 지정하지 않아도
잘 작동했지만 Strong Ref Cursor 는 Cursor 를 선언할 때 반드시 리턴 할 데이터 타입을 지정해
야 합니다. 그래서 Strong Ref Cursor 은 Cursor 로 부터 데이터를 받아서 저장할 데이터 타입을
먼저 선언을 해 놓고 Cursor 를 선언해야 한다는 부분이 Weak Ref Cursor 와 다른 점 입니다.
아래의 실습으로 테스트 해 보겠습니다.
아래의 실습은 emp 테이블에서 empno, ename,job 을 ref cursor 를 사용하여 변수에 담아 출력
하는 예제입니다.
이 예제에서는 여러 컬럼와 여러 로우를 쉽게 저장하기 위해서 record TYPE 변수형을 선언해서
사용했습니다. 물론 이 예처럼 record TYPE 변수를 써야 하는 것은 아니며 다른 변수도 얼마든
사용할 수 있습니다.
위 예에서 알 수 있듯이 Strong ref Cursor 는 Cursor 에서 변수로 값을 돌려줄 때 (Return) 형식
이 지정되어 있어야 하므로 제한적이라고 하는 것입니다. 그러나 Weak ref Cursor 는 형식이 지정
되지 않기 때문에 데이터 형이 다른 다양한 데이터를 선택해서 조회 할 경우 유용하게 사용될
수 있고 현재도 많이 사용되는 Cursor 이므로 꼭 습득하시기 바랍니다.
- SQL CURSOR 연습문제
1. 부서코드를 입력 받아 해당 부서에 속한 사원들을 삭제한 후 삭제된 사원 건수를 출력하세요.
(모든 변수와 커서의 이름은 임의로 지정하세요)
2.명시적 커서를 사용하여 사용자에게 부서코드를 입력 받아 그 부서에 속한 사원들의 이름, 급여
를 출력하세요. (모든 변수와 커서의 이름은 임의로 지정하세요)
3. department 테이블을 조회하여 명시적 커서를 응용해서 아래와 같이 출력하세요.
단 커서이름이나 변수명 등은 각자 임의로 사용하세요.
'[기타SQL] > PL_SQL' 카테고리의 다른 글
6. Oracle Subprogram ★★★ (0) | 2014.10.16 |
---|---|
5. Oracle Exception (예외처리) (0) | 2014.10.15 |
3. PL/SQL 제어문. (0) | 2014.10.13 |
2. PL/SQL 변수. (0) | 2014.10.13 |
1. ORACLE PL/SQL 시작하기 (0) | 2014.10.13 |