CURSOR

[형식] - 단계
  1. CURSOR  cursor_name is query; : 하나 이상의 ROW를 담을 객체
  2. OPEN cursor_name; : 실제 실행 코드에서 커서를 시작한다
  3. LOOP, FETCH를 이용해서 값을 선언된 변수에 대입
  4. CLOSE cursor_name; : 객체를 닫는다. 

명시적 커서 확인(SQL%~)
IF SQL%FOUND THEN
    DBMS_OUTPUT.PUT_LINE('검색한 데이터가 존재한다  ' || V_SAL);
END IF;

CURSOR를 만들어서 SELECT 결과를 저장한 다음, 오픈하고 코드, 클로드한다.
1단계에서 그냥 query만 작성하면 SQL%FOUND, NOTFOUND 등 CURSOR의 속성으로 호출가능

함수는 RETURN에 있는 값을 리턴하지만 
프로시져는 OUT 매개변수에 있는 매개변수를 알아서 리턴

1. SQL%ROWCOUNT : 해당 SQL문에 영향을 받는 행의 수
2. SQL%FOUND : 해당 SQL문에 영향을 받는 행의 수가 1개 이상일 경우 TRUE를 리턴
3. SQL%NOTFOUND : 해당 SQL문에 영향을 받는 행의 수가 없으면 TRUE를 리턴
4. SQL%ISOPEN : 항상 FALSE, 암시적 커서가 열려있는지 유무

 


매개변수로 CURSOR를 받는 경우
[형식]
CREATE OR REPLACE PROCEDURE 프로시져명 ( 매개변수명 IN OUT SYS_REFCURSOR )
OPEN 매개변수명 FOR SELECT EMPNO, ENAME FROM EMP WHERE JOB = P_JOB;

============================================================================

Q1) 부서번호 20번인 사원의 부서번호 이름, 봉급을 구하는 프로시저를 만들어보자
SELECT EMPNO, ENAME, SAL FROM EMP WHERE DEPTNO = 20;

CREATE OR REPLACE PROCEDURE EMP_EX01 AS 

    -- SELECT에서 리턴 받을 변수 선언
    V_EMPNO EMP.EMPNO%TYPE;
    V_ENAME EMP.ENAME%TYPE;
    V_SAL NUMBER(7,2);
    
    -- 1. CURSOR  cursor_name is query; : 하나 이상의 ROW를 담을 객체
    CURSOR EMP_CURSOR IS 
        SELECT EMPNO, ENAME, SAL 
        FROM EMP 
        WHERE DEPTNO = 20;

BEGIN
    -- 2. OPEN cursor_name; : 실제 실행 코드에서 커서를 시작한다
    OPEN EMP_CURSOR;

    -- 3. LOOP, FETCH를 이용해서 값을 선언된 변수에 대입
        LOOP
            FETCH EMP_CURSOR INTO V_EMPNO, V_ENAME, V_SAL;
            EXIT WHEN EMP_CURSOR%NOTFOUND OR EMP_CURSOR%ROWCOUNT > 5;

            DBMS_OUTPUT.PUT_LINE(V_EMPNO);
            DBMS_OUTPUT.PUT_LINE(V_ENAME);
            DBMS_OUTPUT.PUT_LINE(V_SAL);

        END LOOP;

    -- 4. CLOSE cursor_name; : 객체를 닫는다. 
    CLOSE EMP_CURSOR;
END EMP_EX01;


Q2) 사원테이블에서 사원의 이름과 봉급을 출력해보자
SELECT ENAME, SAL FROM EMP;

CREATE OR REPLACE PROCEDURE EX_VIEW AS
    V_ENAME EMP.ENAME%TYPE;
    V_SAL EMP.SAL%TYPE;

    CURSOR C_VIEW IS SELECT ENAME, SAL FROM EMP;

BEGIN
    OPEN C_VIEW;
        LOOP
            FETCH C_VIEW INTO V_ENAME, V_SAL;
            EXIT WHEN C_VIEW%NOTFOUND;
            DBMS_OUTPUT.PUT_LINE(V_ENAME || V_SAL);

        END LOOP;
    CLOSE C_VIEW;
END EX_VIEW;


Q3) 사원테이블에서 커미션이 측정된 사원의 이름, 봉급, 커미션을 출력해보자 EX_VIEW01;
CREATE OR REPLACE PROCEDURE EX_VIEW01 AS 
    R_EMP EMP%ROWTYPE;

    CURSOR RES IS
        SELECT *    -- 1
        FROM EMP
        WHERE COMM IS NOT NULL;

BEGIN
    OPEN RES;
        LOOP
            FETCH RES INTO R_EMP;    -- 2  : 1이랑 2개 개수 같아야 함
            EXIT WHEN RES%NOTFOUND;
            
            dbms_output.put(R_EMP.ENAME || '        ');
            dbms_output.put(R_EMP.SAL || '        ');
            dbms_output.put_line(R_EMP.COMM);
        END LOOP;
    CLOSE RES;
END EX_VIEW01;


Q4) 부서번호를 커서로 전달해서 해당 사원의 번호, 이름, 봉급을 출력해보자
SELECT EMPNO, ENAME, SAL
FROM EMP
WHERE DEPTNO = 10;

CREATE OR REPLACE PROCEDURE EMP_EX04 AS 
    V_EMPNO EMP.EMPNO%TYPE;
    V_ENAME EMP.ENAME%TYPE;
    V_SAL NUMBER(7,2);

    CURSOR EMP_CURSOR (V_DEPTNO NUMBER) IS
        SELECT EMPNO, ENAME, SAL
        FROM EMP
        WHERE DEPTNO = V_DEPTNO;

BEGIN
    OPEN EMP_CURSOR(10);
        LOOP
            FETCH EMP_CURSOR INTO V_EMPNO, V_ENAME, V_SAL;
            EXIT WHEN EMP_CURSOR%NOTFOUND;
            
            DBMS_OUTPUT.PUT(V_EMPNO || '    ');
            DBMS_OUTPUT.PUT(V_ENAME || '    ');
            DBMS_OUTPUT.PUT_LINE(V_SAL || '    ');
        END LOOP;
    CLOSE EMP_CURSOR;
        
    OPEN EMP_CURSOR(10);
        LOOP
            FETCH EMP_CURSOR INTO V_EMPNO, V_ENAME, V_SAL;
            EXIT WHEN EMP_CURSOR%NOTFOUND;
            
            DBMS_OUTPUT.PUT(V_EMPNO || '    ');
            DBMS_OUTPUT.PUT(V_ENAME || '    ');
            DBMS_OUTPUT.PUT_LINE(V_SAL || '    ');
        END LOOP;
    CLOSE EMP_CURSOR;
END EMP_EX04;


Q5) 사원번호를 입력받아 데이터를 확인하고 급여를 1.1배 하는 프로시져를 만들자.
CREATE OR REPLACE PROCEDURE EMP_EX05 (P_EMPNO IN EMP.EMPNO%TYPE) AS 
    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);
        
        UPDATE EMP
        SET SAL = SAL * 1.1
        WHERE EMPNO = P_EMPNO;
        
        V_UPDATE_ROW := SQL%ROWCOUNT;
        DBMS_OUTPUT.PUT_LINE('급여가 인상된 사원의 수  ' || V_UPDATE_ROW);
        
    END IF;
END EMP_EX05;


Q6) 사원번호를 입력해서 무슨 부서인지를 리턴 받아보자. 프로시져
CREATE OR REPLACE PROCEDURE EMP_EX06(P_EMPNO IN EMP.EMPNO%TYPE,
                                                                    V_RES OUT VARCHAR2) 
AS
    V_DEPTNO EMP.DEPTNO%TYPE;

BEGIN
    SELECT DEPTNO INTO V_DEPTNO
    FROM EMP
    WHERE EMPNO = P_EMPNO;
    
    IF V_DEPTNO = 10 THEN
        V_RES := '10번 부서 사원이야';
    ELSIF V_DEPTNO = 20 THEN
        V_RES := '20번 부서 사원이야';
    ELSIF V_DEPTNO = 30 THEN
        V_RES := '30번 부서 사원이야';
    END IF;
        
END EMP_EX06;

VAR RES VARCHAR2(50);
EXEC EMP_EX06(7900, :RES);
PRINT RES;


Q7) 이름을 입력하면 직업을 리턴하는 코드를 작성하자
CREATE OR REPLACE PROCEDURE EMP_EX07 
(
  MY_RES IN OUT VARCHAR2 
) AS 
    V_RES EMP.JOB%TYPE;
BEGIN
    SELECT JOB INTO V_RES
    FROM EMP
    WHERE ENAME = MY_RES;
    
    MY_RES := V_RES;
    
END EMP_EX07;

VAR RES02 VARCHAR2(50);
EXECUTE :RES02 := 'SMITH';
EXECUTE EMP_EX07(:RES02);
PRINT RES02;

Q8) 직업을 입력하면 사번과 이름을 포함하는 객체를 리턴받는 프로시져를 생성
create or replace PROCEDURE EMP_EX08 (p_job varchar2,
  P_EMP_REFCUR IN OUT SYS_REFCURSOR)
AS
BEGIN
  OPEN p_emp_refcur FOR
                    SELECT empno, ename FROM emp WHERE job = p_job;
END EMP_EX08;

VAR EX_08 REFCURSOR;
EXECUTE EMP_EX08('SALESMAN', :EX_08);
PRINT EX_08;


Q9) Q8을 이용해서 사번과 이름을 출력하는 프로시져를 생성
create or replace PROCEDURE EMP_EX09 AS 
V_EMPNO EMP.EMPNO%TYPE;
V_ENAME EMP.ENAME%TYPE;
V_JOB EMP.JOB%TYPE := 'SALESMAN';
V_EMP_REFCUR SYS_REFCURSOR;

BEGIN
    DBMS_OUTPUT.PUT_LINE('EMPLYEES WITH JOB ' || V_JOB );
    DBMS_OUTPUT.PUT_LINE('EMPNO     ENAME');
    DBMS_OUTPUT.PUT_LINE('============================');

    EMP_EX08(V_JOB, V_EMP_REFCUR);
    LOOP
        FETCH V_EMP_REFCUR INTO V_EMPNO, V_ENAME;
        EXIT WHEN V_EMP_REFCUR%NOTFOUND;
        
        DBMS_OUTPUT.PUT_LINE(V_EMPNO || '        ' || V_ENAME);
    
    END LOOP;     
    CLOSE V_EMP_REFCUR;
END EMP_EX09;

EXECUTE EMP_EX09;

'데이터과학자 - 강의 > oracle' 카테고리의 다른 글

210601 oracle - PL/SQL  (0) 2021.06.01
210531 oracle - CONSTRAINT, SEQUENCE  (0) 2021.05.31
210526 oracle - CONSTRAINT, SEQUENCE  (0) 2021.05.28
210526 oracle - Transaction, TCL, DDL  (0) 2021.05.27
210526 oracle - DML  (0) 2021.05.26

+ Recent posts