PL/SQL

PL/SQL 기초 04강 — SQL과 결합: SELECT INTO·DML·암시적 커서

🎯 학습 목표

  • SELECT … INTO로 쿼리 결과를 PL/SQL 변수에 담는다.
  • NO_DATA_FOUND, TOO_MANY_ROWS 예외가 발생하는 상황을 안다.
  • INSERT/UPDATE/DELETE를 PL/SQL 안에서 실행하고 COMMIT/ROLLBACK을 제어한다.
  • 암시적 커서 속성(SQL%ROWCOUNT, SQL%FOUND)으로 DML 결과를 확인한다.

📖 SELECT INTO — 한 행을 변수에 담기

PL/SQL에서 SELECT 결과를 변수에 담으려면 반드시 INTO를 씁니다. 결과가 정확히 한 행이어야 합니다.

DECLARE
  v_name  emp.ename%TYPE;
  v_sal   emp.sal%TYPE;
  v_dept  emp.deptno%TYPE;
BEGIN
  SELECT ename, sal, deptno
    INTO v_name, v_sal, v_dept
    FROM emp
   WHERE empno = 7369;

  DBMS_OUTPUT.PUT_LINE(v_name || ' / 급여: ' || v_sal || ' / 부서: ' || v_dept);
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('해당 사원이 없습니다.');
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('결과가 두 건 이상입니다. 조건을 좁혀 주세요.');
END;
/
  • NO_DATA_FOUND: 결과가 0건일 때 자동 발생.
  • TOO_MANY_ROWS: 결과가 2건 이상일 때 자동 발생.
  • 여러 행을 처리하려면 커서(5강)를 사용해야 합니다.

💻 PL/SQL 안에서 DML

BEGIN
  -- INSERT
  INSERT INTO emp_log(log_id, log_msg, log_dt)
    VALUES (seq_log.NEXTVAL, '신규 사원 추가', SYSDATE);

  -- UPDATE
  UPDATE emp
     SET sal = sal * 1.1
   WHERE deptno = 20;

  -- DELETE
  DELETE FROM emp_log
   WHERE log_dt < SYSDATE - 30;   -- 30일 이전 로그 삭제

  COMMIT;   -- 트랜잭션 확정
  DBMS_OUTPUT.PUT_LINE('처리 완료');
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;   -- 오류 시 전체 취소
    DBMS_OUTPUT.PUT_LINE('오류 발생, 롤백: ' || SQLERRM);
END;
/

COMMIT/ROLLBACK은 PL/SQL 블록 안에서 명시적으로 실행합니다. 블록이 정상 종료해도 자동 커밋되지 않습니다.

📖 암시적 커서와 커서 속성

DML(INSERT/UPDATE/DELETE) 또는 SELECT INTO를 실행하면 오라클은 내부적으로 암시적 커서(Implicit Cursor)를 자동 생성합니다. 이 커서의 속성으로 마지막 SQL의 결과를 확인할 수 있습니다.

BEGIN
  UPDATE emp
     SET sal = sal + 200
   WHERE deptno = 30;

  -- DML 직후 암시적 커서 속성 확인
  IF SQL%FOUND THEN   -- 한 건 이상 영향을 받았으면 TRUE
    DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || '건 업데이트되었습니다.');
  ELSE
    DBMS_OUTPUT.PUT_LINE('업데이트된 행이 없습니다.');
  END IF;

  COMMIT;
END;
/
주요 암시적 커서 속성:
  SQL%FOUND      : 마지막 SQL이 1건 이상 영향을 미쳤으면 TRUE
  SQL%NOTFOUND   : 영향을 미친 행이 없으면 TRUE
  SQL%ROWCOUNT   : 영향을 받은 행 수(숫자)
  SQL%ISOPEN     : 암시적 커서는 항상 FALSE (자동 닫힘)

⚠️ 주의사항

  • SELECT INTO는 반드시 정확히 한 행만 반환해야 합니다. 집계가 없는 SELECT에 WHERE 조건이 느슨하면 TOO_MANY_ROWS가 납니다. 여러 행이 예상된다면 커서(5강)를 쓰세요.
  • COMMIT을 행마다 실행하면 log file sync 대기가 폭증합니다. 가능하면 일괄 처리 후 한 번 COMMIT하세요.
  • ROLLBACK은 해당 트랜잭션의 모든 DML을 취소합니다. SAVEPOINT를 활용하면 일부만 롤백할 수 있습니다.

💡 팁

  • 암시적 커서 속성은 다음 SQL이 실행되면 덮어써집니다. DML 바로 다음 줄에서 확인하세요.
  • SELECT INTO 결과가 1건인지 보장할 수 없을 때는 EXCEPTION 섹션에 NO_DATA_FOUND, TOO_MANY_ROWS를 항상 처리하는 습관을 들이세요.