커서(CURSOR)

  • 커서란 특정 SQL 문장을 처리한 결과를 담고 있는 영역(PRIVATE SQL이라는 메모리 영역)을 가리키는 일종의 포인터로,

    커서를 사용하면 처리된 SQL 문장의 결과 집합에 접근할 수 있다.

-- 1) 묵시적 커서 ( SQL 커서)
-- 오라클 내부에서 자동으로 생성되어 사용하는 커서로,
-- SQL 문장(INSERT, UPDATE, MERGE, DELETE, SELECT INTO)이 실행될 때마다 자동으로 만들어져 사용된다.

-- 묵시적 커서와 커서속성
DECLARE
    VN_DEPARTMENT_ID EMPLOYEES.DEPARTMENT_ID%TYPE := 80;
BEGIN
    -- 부서ID가 80인 데이터를 자신의 이름으로 수정
    UPDATE EMPLOYEES
        SET EMP_NAME = EMP_NAME
    WHERE DEPARTMENT_ID = VN_DEPARTMENT_ID; -- 34건 발생

    -- 업데이트 했던 데이터 변경이 몇건이 발생했는지 확인    
    DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
    COMMIT;
END;

-- 2) 명시적 커서

-- 2-1) 익명블록
DECLARE -- 변수, 상수, 커서 선언
    VS_EMP_NAME EMPLOYEES.EMP_NAME%TYPE;
    VN_CNT NUMBER := 0;
    
    -- 커서선언
    CURSOR CUR_EMP_DEP (CP_DEPARTMENT_ID EMPLOYEES.DEPARTMENT_ID%TYPE)
    IS
    SELECT EMP_NAME
    FROM EMPLOYEES
    WHERE DEPARTMENT_ID = CP_DEPARTMENT_ID;
    
BEGIN
    -- 커서오픈(실행)
    OPEN CUR_EMP_DEP(90);
    
    LOOP
    -- 커서패치 작업 (메모리상의 데이터를 읽어오는 의미)
        FETCH CUR_EMP_DEP INTO VS_EMP_NAME;
        
        VN_CNT := VN_CNT + 1;
        DBMS_OUTPUT.PUT_LINE(VN_CNT);
        
        -- 커서영역에 현재의 포인터가 더이상 참조데이터 행이 없는경우 LOOP탈출
        EXIT WHEN CUR_EMP_DEP%NOTFOUND; -- 현재 FETCH의 상태를 확인
        
        DBMS_OUTPUT.PUT_LINE(VS_EMP_NAME);

    END LOOP;
    
    CLOSE CUR_EMP_DEP;
    
END;

커서와 FOR문

기본 FOR 구문 형식

    FOR 인덱스 IN [REVERSE]초깃값..최종값
    LOOP
      처리문;
    END LOOP;
커서와 함께 FOR문을 사용할 때는, “초깃값..최종값” 대신 커서가 위치한다.

커서와 함께 사용될 경우 FOR 구문 형식

    FOR 레코드 IN 커서명(매개변수1, 매개변수2, ...)
    LOOP
      처리문;
    END LOOP;
-- 1)
DECLARE
    -- 커서 선언
    CURSOR CUR_EMP_DEP (CP_DEPARTMENT_ID EMPLOYEES.DEPARTMENT_ID%TYPE)
    IS
    SELECT EMPLOYEE_ID, EMP_NAME FROM EMPLOYEES
    WHERE DEPARTMENT_ID = CP_DEPARTMENT_ID;
BEGIN
    -- 내부적으로 커서 OPEN이 사용
    -- FOR문을 통한 커서 패치작업 (OPEN - FETCH - CLOSE)
    FOR EMP_REC IN CUR_EMP_DEP(90) -- 1) OPEN 커서 2) 데이터행을 EMP_REC 레코드변수가 참조
    LOOP
        DBMS_OUTPUT.PUT_LINE('사원번호 : ' || EMP_REC.EMPLOYEE_ID);
        DBMS_OUTPUT.PUT_LINE('사원이름 : ' || EMP_REC.EMP_NAME);
    END LOOP;
END;



-- 2) FOP문으로 패치(커서의 내용을 포함). 레코드명사용. 예) 레코드명.컬럼명 참조
DECLARE
    
BEGIN
    -- 내부적으로 커서 OPEN이 사용
    -- FOR문을 통한 커서 패치작업 (OPEN - FETCH - CLOSE)
    FOR EMP_REC IN (
                    -- 커서내용
                    SELECT EMPLOYEE_ID, EMP_NAME 
                    FROM EMPLOYEES
                    WHERE DEPARTMENT_ID = 90)
    LOOP
        DBMS_OUTPUT.PUT_LINE('사원번호 : ' || EMP_REC.EMPLOYEE_ID);
        DBMS_OUTPUT.PUT_LINE('사원이름 : ' || EMP_REC.EMP_NAME);
    END LOOP;
END;

커서변수 타입

-- 커서변수를 정의하기 위한 데이터 타입

-- 1) 약한 커서타입
-- TYPE 커서_타입명 IS REF CURSOR;
-- 2) 강한 커서타입 : 커서변수가 갖게 되는 SELECT문
-- TYPE 커서_타입명 IS REF CURSOR [ RETURN 반환 타입 ];
DECLARE
    VS_EMP_NAME EMPLOYEES.EMP_NAME%TYPE;
    
    -- 약한 커서타입 선언
    TYPE EMP_DEP_CURTYPE IS REF CURSOR;
    -- 커서변수선언. 예) 커서변수명 커서약한 또는 강한 데이터타입
    EMP_DEP_CURVAR EMP_DEP_CURTYPE;
    
BEGIN
    OPEN EMP_DEP_CURVAR FOR SELECT EMP_NAME
                            FROM EMPLOYEES
                            WHERE DEPARTMENT_ID = 90;
    LOOP
        FETCH EMP_DEP_CURVAR INTO VS_EMP_NAME;
        
        EXIT WHEN EMP_DEP_CURVAR%NOTFOUND;
        
        DBMS_OUTPUT.PUT_LINE('TEST');    
    END LOOP;
    
END;

커서변수를 매개변수로 전달하기

-- 커서변수를 매개변수로 전달하기
DECLARE
    EMP_DEP_CURVAR SYS_REFCURSOR; -- 약한 커서타입

    -- 사원명을 받아오기 위한 변수선언
    VS_EMP_NAME EMPLOYEES.EMP_NAME%TYPE;
    
    -- 임시 프로시저 선언(정의)
    PROCEDURE TEST_CURSOR_ARGU(P_CURVAR IN OUT SYS_REFCURSOR)
    IS
        C_TEMP_CURVAR SYS_REFCURSOR;
    BEGIN
        OPEN C_TEMP_CURVAR FOR SELECT EMP_NAME
                               FROM EMPLOYEES
                               WHERE DEPARTMENT_ID = 90;
        P_CURVAR := C_TEMP_CURVAR;        
    END;
    
BEGIN
    -- 프로시저 호출. EMP_DEP_CURVAR 매개변수로 제공한 커서변수가 임시프로시저 내부의 C_TEMP_CURVAR 참조
    TEST_CURSOR_ARGU(EMP_DEP_CURVAR);
    
    LOOP
        FETCH EMP_DEP_CURVAR INTO VS_EMP_NAME;
        
        EXIT WHEN EMP_DEP_CURVAR%NOTFOUND;
        
        DBMS_OUTPUT.PUT_LINE(VS_EMP_NAME);
    END LOOP;
END;

태그:

카테고리:

업데이트:

댓글남기기