[PL/SQL] 예외처리

HyunDong Lee·2022년 9월 19일
0

PL/SQL

목록 보기
5/8
post-thumbnail

예외처리

PL/SQL 코드를 작성 시 발생할 수 있는 오류

  • 문법오류(컴파일 오류)
    • 키워드 이름, 객체, 프로시저, 함수 등 일반적인 프로그래밍 오류
  • 런타임 오류
    • 컴파일 시에는 아무런 문제가 없지만 실행을 시킬 때 발생하는 오류이다.
    • 예외처리를 통해 제어해야 함.

예외처리 구문

EXCEPTION WHEN 예외명1 THEN 예외처리 구문1
		WHEN 예외명2 THEN 예외처리 구문2
        ...
        ;
  • CASE문과 유사한 구조

아래 예제를 통해 DIVISION 에러를 발생시켜보자.

SET SERVEROUTPUT ON;

DECLARE
    vi_num number := 0;
BEGIN
    vi_num := 10 /0;
    dbms_output.put_line('success!!');
    EXCEPTION when others then
        dbms_output.put_line('오류가 발생했습니다');
END;

SET SERVEROUTPUT ON;

DECLARE
    vi_num number := 0;
BEGIN
    vi_num := 10 /0;
    dbms_output.put_line('success!!');
    EXCEPTION when others then
        dbms_output.put_line('오류가 발생했습니다');
END;

/

SET SERVEROUTPUT ON;


    CREATE OR REPLACE PROCEDURE ch10_exception_proc
    IS
       vi_num NUMBER := 0;
    BEGIN
      vi_num := 10 / 0;
      DBMS_OUTPUT.PUT_LINE('Success!');

    EXCEPTION WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('오류가 발생했습니다');
    END;

/

SET SERVEROUTPUT ON;

declare
    vi_num number := 0;
begin
    ch10_exception_proc;
    dbms_output.put_line('Success!');
end;

SQLCODE, SQLERRM

  • SQLCODE

    • 실행부에서 발생한 예외에 해당하는 코드를 반환한다
  • SQLERRM

    • 발생한 예외에 대한 오류 메시지를 반환한다

사용자 정의 예외 처리

  1. 예외 정의 : 사용자정의예외명 EXCEPTION;
  2. 예외 발생 :RAISE 사용자정의예외명;
  3. 발생된 예외 처리 :EXCEPTION WHEN 사용자정의예외명 THEN ...
select count(*)

시스템 예외에 이름 부여하기

  • 시스템 예외에는 ZERO_DIVIDE, INVALID_NUMBER 같이 미리 정의된 예외가 있었다. 하지만 이들처럼 예외명이 부여된 것은 시스템 예외 중 극소수이고 나머지는 예외코드만 존재한다.

  • 예외 이름이 없는 이런 예외에 이름을 부여하면 코드가 훨씬 읽기 편할 뿐만 아니라, 해당 코드의 ㅗㄹ직을 파악하는 것도 아주 쉬워진다.

CREATE OR REPLACE PROCEDURE ch10_ins_emp_proc (
      p_emp_name employees.emp_name%TYPE,
      p_department_id departments.department_id%TYPE,
      p_hire_month  VARCHAR2  )
    IS
      vn_employee_id employees.employee_id%TYPE;
      vd_curr_date    DATE := SYSDATE;
      vn_cnt          NUMBER := 0;

      ex_invalid_depid EXCEPTION; -- 잘못된 부서번호일 경우 예외 정의

      ex_invalid_month EXCEPTION; -- 잘못된 입사월인 경우 예외 정의
      PRAGMA EXCEPTION_INIT ( ex_invalid_month, -1843); -- 예외명과 예외코드 연결
    BEGIN
      -- 부서테이블에서 해당 부서번호 존재유무 체크
      SELECT COUNT(*)
        INTO vn_cnt
        FROM departments
       WHERE department_id = p_department_id;

      IF vn_cnt = 0 THEN
         RAISE ex_invalid_depid; -- 부서코드 사용자 정의 예외 발생
      END IF;

      -- 입사월 체크(1~12월 범위를 벗어났는지 체크)
      IF SUBSTR(p_hire_month, 5, 2) NOT BETWEEN '01' AND '12' THEN
        RAISE ex_invalid_month; -- 잘못된 입사월 사용자 정의 예외 발생
      END IF;

      -- employee_id의 max 값에 +1
      SELECT MAX(employee_id) + 1
        INTO vn_employee_id
        FROM employees;

      -- 사용자예외처리 예제이므로 사원 테이블에 최소한 데이터만 입력함
      INSERT INTO employees ( employee_id, emp_name, hire_date, department_id )
                  VALUES ( vn_employee_id, p_emp_name, TO_DATE(p_hire_month || '01'), p_department_id );

      COMMIT;

    EXCEPTION 
    WHEN ex_invalid_depid THEN -- 사용자 정의 예외 처리
      DBMS_OUTPUT.PUT_LINE('해당 부서번호가 없습니다');
    WHEN ex_invalid_month THEN -- 입사월 사용자 정의 예외 처리
      DBMS_OUTPUT.PUT_LINE(SQLCODE);
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
      DBMS_OUTPUT.PUT_LINE('1~12월 범위를 벗어난 월입니다');
    WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;

효율적인 예외처리 방법

  • 시스템 예외인 경우는 others를 이용하는 것이 좋다.
  • 미리 정의된 예외는 exception절에 명시해 사용할 수 있지만, others는 모든 시스템 예외를 잡아내므로 sqlcode와 sqlerrm을 적극 사용하는게 권장된다.
  • 예외 초리 루틴을 공통 모듈화하고, 발생된 예외 로그를 남기자
  • 사용자 정의 예외도 별도의 테이블로 미리 만들어 관리하자
    CREATE TABLE app_user_define_error (
      error_code    NUMBER,               -- 에러코드
      error_message VARCHAR2(300),        -- 에러 메시지
      create_date   DATE DEFAULT SYSDATE, -- 등록일자
                   PRIMARY KEY (error_code)
      );
      
    INSERT INTO app_user_define_error ( error_code, error_message )  
      VALUES (-1843, '지정한 월이 부적합합니다');
    INSERT INTO app_user_define_error ( error_code, error_message )
      VALUES (-20000, '해당 부서가 없습니다');

    COMMIT;

0개의 댓글