hyeonga_code

Database_85_PL/SQL_제어 구조_CURSOR 본문

Oracle Database

Database_85_PL/SQL_제어 구조_CURSOR

hyeonga 2023. 8. 31. 07:59
반응형

-- PL/SQL 제어 구조

    -- CURSOR
        -- Oracle Server에서 할당한 전용 메모리 영역에 대한 포인터입니다.
        -- 실행되는 모든 SQL 문에는 연관된 개별 커서가 있습니다.
            -- PGA 안에 위치한 Private SQL 작업 영역을 사용하여 SQL 문을 실행하고 처리 정보를 저장합니다.
            -- 커서를 사용하여 전용 SQL 영역에 이름을 부여하고 저장된 정보에 엑세스 할 수 있습니다.
            -- 커서를 열어 질의에 의해 반환되는 행을 처리한 후 커서를 닫습니다.
        -- SELECT 문의 결과 집합을 처리하는 데에 사용합니다.
        -- 유형
            -- 암시적 커서 : SQL문을 처리하기위해 내부적으로 생성, 관리합니다.
                -- 예외 처리 시 많이 사용됩니다.
            -- 명시적 커서 : 프로그래머가 명시적으로 선언합니다.
                -- 여러 SELECT 문에 의해 반환된 각 행을 개별적으로 처리할 수 있습니다.
                -- 특정 SQL 문을 처리하기 위해 생성하는 포인터입니다.
                -- 기능
                    -- 질의에 의해 반환된 행을 첫 번째 행부터 차례로 처리할 수 있습니다.
                    -- 현재 처리중인 행을 추적합니다.
                    -- 프로그래머가 PL/SQL 블록에서 명시적 커서를 수동으로 제어할 수 있습니다.
                -- 제어
                    -- DECLARE : 명명된 SQL 영역을 생성합니다.
                    -- OPEN : 활성 집합을 식별합니다.
                    -- FETCH : 현재 행을 변수에 로드합니다.
                    -- EMPTY? : 기존 행에 대해 테스트하고, 행이 있는 경우 FETCH로 돌아갑니다.
                    -- CLOSE : 결과행 집합을 해제합니다.
                -- 구문
                    /*
                    -- 선언
                    CURSOR cursor_name IS
                        select_statement;
                        
                    -- 커서 열기
                    OPEN cursor_name;
                    
                    -- 데이터 패치_FETCH
                    FETCH cursor_name INTO  [ variable1 [, variable2, ... ] | record_name ];
                        -- 현재 행 값을 변수로 가져옵니다.
                            -- FETCH 문은 활성 집합에 있는 행을 한 번에 하나씩 검색합니다.
                            -- 행을 인출하고 나면 커서는 활성 집합의 다음 행으로 이동합니다.
                        -- 커서의 행 포함 여부를 테스트합니다.
                            -- 반복문을 사용하여 해당 커서의 참조가 모두 끝난 경우 반복문을 빠져나와야 합니다.
                            -- cursor_name%NOTFOUND 커서 속성을 사용하여 루프를 벗어납니다.
                    -- 커서 닫기
                    CLOSE cursor_name;
                    */
        -- 커서 속성
            -- SQL%FOUND
                -- 유형 : BOOLEAN
                -- 결과 집합의 패치 로우 수가 1개 이상이면 TRUE, 아니면 FALSE를 반환합니다.
            -- SQL%NOTFOUND
                -- 유형 : BOOLEAN
                -- 결과 집합의 패치 로우 수가 0개이면 TRUE, 아니면 FALSE를 반환합니다.
            -- SQL%ROWCOUNT
                -- 유형 : 숫자
                -- 영향을 받은 결과 집합의 로우 수를 반환하고 없으면 0을 반환합니다.
            -- SQL%ISOPEN
                -- 유형 : BOOLEAN
                -- 묵시적 커서는 항상 FALSE를 반환합니다.
                    -- 참조할 때 이미 해당 묵시적 커서는 닫힌 상태 이후입니다.

-- 커서를 사용하는 이유
DECLARE
    v_fname VARCHAR2(25);
BEGIN
    SELECT first_name INTO v_fname
    FROM employees
    WHERE department_id=60;
    DBMS_OUTPUT.PUT_LINE('First Name is : ' || v_fname);
END;
/   
    /*
        -----<오류>--------------------------------------------------------------------
        오류 보고 -
        ORA-01422: exact fetch returns more than requested number of rows
        ORA-06512: at line 4
        01422. 00000 -  "exact fetch returns more than requested number of rows"
        *Cause:    The number specified in exact fetch is less than the rows returned.
        *Action:   Rewrite the query or change number of rows requested
        -------------------------------------------------------------------------------
            -- 넘어오는 값의 개수가 보다 많습니다.
            -- 현재까지 작업한 SQL 문은 하나의 값만을 조회할 수 있습니다.
    */

    -- 암시적 커서
-- SQL%ROWCOUNT 커서 속성을 사용해서 해당 SQL문으로 인해 실제 처리된 결과 행 수를 참조합니다.
DECLARE
    vn_department_id employees.department_id%TYPE := 80;
BEGIN
        -- 80번 부서의 사원이름을 자신의 이름으로 갱신
    UPDATE employees
    SET last_name = last_name
    WHERE department_id = vn_department_id;
        
        -- 몇 건의 데이터가 갱신됐는지 출력
    DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || '행이 갱신되었습니다');
    COMMIT;
END;
/
    /*
    5행이 갱신되었습니다.
    
    PL/SQL 프로시저가 성공적으로 완료되었습니다.
    */

    -- 명시적 커서 사용
DECLARE 
    CURSOR c_emp_cursor IS --커서선언
    SELECT employee_id, last_name FROM employees
    WHERE department_id = 50;
    v_emp_record c_emp_cursor%ROWTYPE;
BEGIN
    OPEN c_emp_cursor; --커서오픈
    LOOP
        FETCH c_emp_cursor INTO v_emp_record; --패치
        EXIT WHEN c_emp_cursor%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE( v_emp_record.employee_id || ' ' || v_emp_record.last_name);
    END LOOP;
    CLOSE c_emp_cursor; --커서닫기
END;
/
    /*
    107 Lorentz
    124 Mourgos
    141 Rajs
    142 Davies
    143 Matos

    
    PL/SQL 프로시저가 성공적으로 완료되었습니다.
    */

    -- 커서 FOR LOOP 를 사용하여 패치를 사용할 필요가 없습니다.
DECLARE
    CURSOR c_emp_cursor IS 
    SELECT employee_id, last_name FROM employees
    WHERE department_id =50; 
BEGIN
    FOR emp_record IN c_emp_cursor -- implicit open and implicit fetch occur
    LOOP
        DBMS_OUTPUT.PUT_LINE( emp_record.employee_id || ' ' || emp_record.last_name); 
    END LOOP;
END;
/
    /*
    107 Lorentz
    124 Mourgos
    141 Rajs
    142 Davies
    143 Matos

    
    PL/SQL 프로시저가 성공적으로 완료되었습니다.
    */

반응형