본문 바로가기
DATABASE/Oracle

[DB] Cursor

by melll93 2023. 1. 18.

1. 커서(Cursor)란?

  • 커서는 Private SQL의 작업 영역이다.
  • 오라클 서버에 의해 실행되는 SQL문은 연관된 각각의 커서를 소유하고 있다.
  • 커서의 종류
    - 암시적 커서 : 모든 DML과 PL/SQL SELECT문에 대해 자동 선언된다.
    - 명시적 커서 : 프로그래머에 의해 선언되며, 이름이 있는 커서이다.

 

2. 암시적 커서(Implicit Cursor)

  • 암시적 커서는 Oracle이나 PL/SQL 실행 메커니즘에 의해 SQL 문장이 처리되는 곳에 대한 익명의 주소이다. Oracle에서 실행되는 모든 SQL문에는 암시적 커서가 생성되며, 커서 속성을 사용할 수 있다. 암시적 커서는 OPEN과 CLOSE가 자동으로 실행된다.
  • 암시적 커서의 속성
    - SQL%ISOPEN : 암시적 커서가 열려 있는지 판단. 항상 FALSE
    - SQL%FOUND : 해당 SQL문에 영향을 받는 행이 존재하면 TRUE
    - SQL%NOTFOUND : 해당 SQL문에 영향을 받는 행이 존재하지 않으면 TRUE
    - SQL%ROWCOUNT : 해당 SQL 문에 영향을 받는 행의 수
  • 암시적 커서 예제
CREATE OR REPLACE PROCEDURE Implicit_Cursor
	(p_empno IN emp.empno%TYPE)

	IS
	v_sal  emp.sal%TYPE;
	v_update_row NUMBER;

	BEGIN
		SELECT sal
		  INTO v_sal
		  FROM emp
		 WHERE empno = p_empno;

		-- 검색된 데이터가 있을경우
		IF  SQL%FOUND THEN     
			DBMS_OUTPUT.PUT_LINE('검색한 데이터가 존재합니다 : '||v_sal);
		END IF;

		UPDATE emp
		SET sal = sal*1.1
		WHERE empno = p_empno;

		-- 수정한 데이터의 카운트를 변수에 저장
		v_update_row := SQL%ROWCOUNT;
		DBMS_OUTPUT.PUT_LINE('급여가 인상된 사원 수 : '|| v_update_row);
        
	EXCEPTION    
		WHEN   NO_DATA_FOUND  THEN  
		DBMS_OUTPUT.PUT_LINE(' 검색한 데이터가 없네요... ');

END;
/
============정상처리 결과============
SQL> set serveroutput on;
SQL> exec implicit_cursor(7369);
검색한 데이터가 존재합니다 : 800
급여가 인상된 사원 수 : 1

PL/SQL 처리가 정상적으로 완료되었습니다.

============예외처리 결과============
SQL> exec implicit_cursor(733223);
검색한 데이터가 없네요...

PL/SQL 처리가 정상적으로 완료되었습니다.

 

 

3. 명시적 커서(Explicit Cursor)

  • Declare => Open => Fetch => Close
  • 명시적 커서의 속성
    - SQL%ISOPEN : 커서가 OPEN 되어 있으면 TRUE
    - SQL%FOUND : FETCH한 데이터가 행을 반환하면 TRUE
    - SQL%NOTFOUND : FETCH한 데이터가 행을 반환하지 않으면 TRUE
    - SQL%ROWCOUNT : 현재까지 반환된 모든 데이터 행의 수
  • 명시적 커서 예제
-- 특정 부서의 평균급여와 사원수를 출력
CREATE OR REPLACE PROCEDURE ExpCursor_Test 
	(v_deptno IN  dept.deptno%TYPE)

	IS
		-- DECLARE
		CURSOR dept_avg IS
		SELECT b.dname, COUNT(a.empno) cnt, 
			ROUND(AVG(a.sal),3) salary
		  FROM emp a, dept b
		 WHERE a.deptno = b.deptno
		   AND b.deptno = v_deptno
		 GROUP BY b.dname ;

		-- FETCH하기 위한 변수 선언
		v_dname dept.dname%TYPE;
		emp_cnt NUMBER;
		sal_avg NUMBER;

	BEGIN
		-- OPEN
		OPEN dept_avg;

		-- FETCH
		FETCH dept_avg INTO v_dname, emp_cnt, sal_avg;
        
		DBMS_OUTPUT.PUT_LINE('부서명 : ' || v_dname);
		DBMS_OUTPUT.PUT_LINE('사원수 : ' || emp_cnt);
		DBMS_OUTPUT.PUT_LINE('평균급여 : ' || sal_avg);

		-- CLOSE
		CLOSE dept_avg;      

	EXCEPTION
		WHEN OTHERS THEN
		DBMS_OUTPUT.PUT_LINE(SQLERRM||'에러 발생 ');
END;
/

============정상처리 결과============
SQL> set serveroutput on;
SQL> execute expcursor_test(30);
부서명 : SALES
사원수 : 6
평균급여 : 1566.667

PL/SQL 처리가 정상적으로 완료되었습니다.

============예외처리 결과============
SQL> execute expcursor_test(40);
부서명 :
사원수 :
평균급여 :

PL/SQL 처리가 정상적으로 완료되었습니다.

예외처리가 정상적으로 됬다면, '에러 발생'이 호출되었어야 하나, 이번 경우에는 제대로 작동하지 않았다.
그 이유에 대해서는 좀 더 공부해본 후 다시 수정하여 올리도록 하겠다.


[참조문서]
https://docs.oracle.com/cd/B13789_01/appdev.101/b10807/06_ora.htm#i45507

반응형

'DATABASE > Oracle' 카테고리의 다른 글

[DB] Function & Procedure & Trigger (Oracle)  (0) 2023.01.14
[DB] PL/SQL 기초 (Oracle)  (0) 2023.01.13
[DB] Table Join (Oracle)  (0) 2023.01.09
[DB] Optimizer & SQL 힌트문 (Oracle)  (1) 2023.01.05

댓글