PL/SQL

PL/SQL 기초 05강 — 명시적 커서

🎯 학습 목표

  • 명시적 커서의 네 단계(DECLARE/OPEN/FETCH/CLOSE)를 작성한다.
  • %NOTFOUND로 FETCH 루프를 안전하게 종료한다.
  • 커서 FOR 루프로 더 간결하게 여러 행을 처리한다.
  • 파라미터가 있는 커서를 만들고 호출한다.

📖 왜 명시적 커서가 필요한가

SELECT INTO는 결과가 정확히 한 행일 때만 쓸 수 있습니다. 여러 행을 한 건씩 꺼내 처리하려면 명시적 커서(Explicit Cursor)를 사용합니다. 커서는 결과 집합을 가리키는 포인터로, FETCH를 호출할 때마다 한 행씩 가져옵니다.

💻 OPEN / FETCH / CLOSE 패턴

DECLARE
  -- 1) DECLARE: 커서 선언 (SQL 정의)
  CURSOR c_emp IS
    SELECT empno, ename, sal
      FROM emp
     WHERE deptno = 20
     ORDER BY sal DESC;

  v_empno emp.empno%TYPE;
  v_ename emp.ename%TYPE;
  v_sal   emp.sal%TYPE;
BEGIN
  -- 2) OPEN: 커서 열기 (쿼리 실행, 결과 집합 준비)
  OPEN c_emp;

  LOOP
    -- 3) FETCH: 한 행 가져와서 변수에 담기
    FETCH c_emp INTO v_empno, v_ename, v_sal;

    -- 더 가져올 행이 없으면 EXIT (FETCH 직후 바로 확인)
    EXIT WHEN c_emp%NOTFOUND;

    DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename || ' 급여: ' || v_sal);
  END LOOP;

  -- 4) CLOSE: 커서 닫기 (자원 반납)
  CLOSE c_emp;
END;
/

📖 커서 속성

커서명%FOUND      : 마지막 FETCH가 행을 가져왔으면 TRUE
커서명%NOTFOUND   : 마지막 FETCH가 행을 못 가져왔으면 TRUE (루프 종료 조건)
커서명%ROWCOUNT   : 지금까지 FETCH한 행 수
커서명%ISOPEN     : 커서가 열려 있으면 TRUE

💻 커서 FOR 루프 — 가장 간결한 방법

커서 FOR 루프는 OPEN·FETCH·CLOSE를 자동으로 처리합니다. 대부분의 경우 이 방법이 가장 간결하고 안전합니다.

-- 커서를 미리 선언하지 않아도 인라인으로 쓸 수 있음
BEGIN
  FOR r IN (SELECT empno, ename, sal
              FROM emp
             WHERE deptno = 20
             ORDER BY sal DESC) LOOP
    DBMS_OUTPUT.PUT_LINE(r.empno || ' ' || r.ename || ' 급여: ' || r.sal);
  END LOOP;
  -- 루프가 끝나면 커서가 자동으로 닫힘
END;
/

레코드 변수 r은 자동 선언되며, r.컬럼명으로 각 필드에 접근합니다.

💻 파라미터 커서

DECLARE
  -- 부서 번호를 파라미터로 받는 커서
  CURSOR c_dept_emp(p_deptno emp.deptno%TYPE) IS
    SELECT ename, sal FROM emp WHERE deptno = p_deptno;
BEGIN
  DBMS_OUTPUT.PUT_LINE('=== 부서 10 ===');
  FOR r IN c_dept_emp(10) LOOP
    DBMS_OUTPUT.PUT_LINE(r.ename || ': ' || r.sal);
  END LOOP;

  DBMS_OUTPUT.PUT_LINE('=== 부서 30 ===');
  FOR r IN c_dept_emp(30) LOOP
    DBMS_OUTPUT.PUT_LINE(r.ename || ': ' || r.sal);
  END LOOP;
END;
/

파라미터 커서는 같은 SQL 구조로 다른 값에 대해 반복 사용할 때 편리합니다.

⚠️ 주의사항

  • OPEN한 커서는 반드시 CLOSE해야 자원(세션 메모리)이 반납됩니다. 커서 FOR 루프는 자동으로 닫아 줍니다.
  • FETCH 직후 EXIT WHEN %NOTFOUND를 두지 않으면 마지막으로 가져온 행을 두 번 처리할 수 있습니다. FETCH 직후에 반드시 확인하세요.
  • 이미 열려 있는 커서를 다시 OPEN하면 오류가 납니다. %ISOPEN으로 확인 후 열거나 먼저 CLOSE하세요.

💡 팁

  • 단순 반복 처리라면 커서 FOR 루프(인라인 포함)를 기본으로 쓰세요. OPEN/FETCH/CLOSE 패턴은 중간에 루프를 특수하게 제어해야 할 때만 씁니다.
  • 커서를 쓰는 것보다 하나의 UPDATE/INSERT … SELECT로 집합 처리하는 게 빠를 때가 많습니다. “정말 행마다 다른 처리가 필요한가?”를 먼저 검토하세요.