(4)PL/SQL 예외처리

PL/SQL의 예외처리 사용법


시작하기 전에

사용 교재 : 오라클SQL과 PL/SQL을 다루는 기술 (https://thebook.io/006696/)

예제 코드 : https://github.com/gilbutITbook/006696


SERVEROUTPUT 설정

PL/SQL 결과물을 보기 위해 아래의 실행문을 실행

SET SERVEROUTPUT ON;

예외처리

예외(exception)란 런타임 때 로직을 처리하면서 발생하는 오류를 말한다

예외는 오라클에서 발생시키는 시스템 예외

사용자가 의도적으로 발생시킬 수 있는 사용자 정의 예외로 구분할 수 있다


예외처리 기본 구조

EXCEPTION WHEN 예외명1 THEN 예외처리 구문 1
WHEN 예외명2 THEN 예외처리 구문 2

			...

WEHN OTHERS THEN 예외처리 구문 n;

WHEN 다음에 위치하는 예외명은 시스템 예외명사용자가 직접 정의한 예외명만 사용할 수 있다.


예외처리 기본 예제


  • 예외처리 없는 프로시저
-- 예외처리 없는 프로시저
CREATE OR REPLACE PROCEDURE no_exception_proc
IS
    vi_num NUMBER := 0;

BEGIN
    vi_num := 10 / 0;
    DBMS_OUTPUT.PUT_LINE('Success!');

END;
/


----------------------------------------------


--예외처리가 없는 프로시저 실행
DECLARE
BEGIN
    no_exception_proc;
    DBMS_OUTPUT.PUT_LINE('프로시저 실행!');

END;
/

1

오류가 발생하여 프로시저가 실행되지 않는다


  • 예외처리 있는 프로시저
-- 예외처리 있는 프로시저
CREATE OR REPLACE PROCEDURE 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;
/

----------------------------------------------

--예외처리가 있는 프로시저 실행
DECLARE
BEGIN
    exception_proc;
    DBMS_OUTPUT.PUT_LINE('프로시저 실행!');

END;
/

2

예외처리부가 실행되고 프로시저도 실행됨


시스템 예외처리

  • 시스템 예외
    • 숫자를 0으로 나눈다거나 SELECT INTO 절을 사용해 데이터를 가져올 때 조건에 만족하는 데이터가 없을때 발생하는 예외 등등
    • 대표적인 시스템 예외명들 : https://thebook.io/006696/part02/ch10/01/03/


시스템 예외처리 예제 1

  • exception_proc 확장
  • 시스템 예외 - ZERO_DIVIDE (0으로 나눔)
  • SQLCODE와 SQLERRM 이용한 예외정보 참조
    • SQLCODE : 에러 코드
    • SQLERRM : 에러 메시지
-- 시스템 예외처리 ZERO_DIVIDE
CREATE OR REPLACE PROCEDURE exception_proc
IS
    vi_num NUMBER := 0;

BEGIN
    vi_num := 10 / 0;
    DBMS_OUTPUT.PUT_LINE('Success!');


    -- ZERO_DIVIDE 오류
    EXCEPTION 
    WHEN ZERO_DIVIDE THEN
        DBMS_OUTPUT.PUT_LINE('ZERO_DIVIDE 오류 발생!');
        DBMS_OUTPUT.PUT_LINE( 'SQL ERROR CODE: ' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE( 'SQL ERROR MESSAGE: ' || SQLERRM);
		
    -- 다른 오류
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('다른 오류 발생!');
        DBMS_OUTPUT.PUT_LINE( 'SQL ERROR CODE: ' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE( 'SQL ERROR MESSAGE: ' || SQLERRM);

END;
/

-- 프로시저 실행
EXEC exception_proc;

3


시스템 예외처리 2

  • 시스템 예외 - NO_DATA_FOUND (데이터가 없음)
-- no_jobid_proc
CREATE OR REPLACE PROCEDURE no_jobid_proc(
    p_employee_id employees.employee_id%TYPE,
    p_job_id      jobs.job_id%TYPE
)
IS
    vn_cnt NUMBER := 0;
    
BEGIN
    SELECT 1
    INTO vn_cnt
    FROM jobs
    WHERE job_id = p_job_id;
    
    UPDATE employees
    SET job_id = p_job_id
    WHERE employee_id= p_employee_id;
    
    COMMIT;

    EXCEPTION 
    
    -- NO_DATA_FOUND
    WHEN NO_DATA_FOUND THEN
                 DBMS_OUTPUT.PUT_LINE(SQLERRM);
                 DBMS_OUTPUT.PUT_LINE(p_job_id ||'에 해당하는 job_id가 없습니다');
    WHEN OTHERS THEN
                 DBMS_OUTPUT.PUT_LINE('기타 에러: ' || SQLERRM);
END;
/

-- 프로시저 실행
EXEC no_jobid_proc(200, 'SM_JOB4');

4

jobs 테이블에 해당하는 데이터가 없기 때문에 예외처리문이 수행된다.


사용자 정의 예외처리


사용자 정의 예외

사용자가 직접 예외를 정의해서 사용하는 것


  • 사용자 정의 예외를 사용하는 이유
    • 예외명이 부여된 것은 시스템 예외 중 극소수
    • 이름이 없는 예외에 이름을 부여하면 코드가 훨씬 읽기 편함
    • 해당 코드의 로직을 파악하는 것도 쉬워짐


사용자 정의 예외 사용법

  1. 예외 정의 : 사용자_정의_예외명 EXCEPTION;
    • 사용자 예외를 사용하려면 PL/SQL 블록의 선언부에 예외를 정의
  2. 예외 발생시키기 : RAISE 사용자_정의_예외명;
    • 시스템 예외는 자동으로 검출되지만, 사용자 예외는 위의 형태처럼 발생시킴
  3. 발생된 예외 처리 : EXCEPTION WHEN 사용자_정의_예외명 THEN
    • 예외를 발생시키면 자동으로 제어권이 EXCEPTION 절로 넘어옴


예제

  • 신규 사원을 INSERT할때 오류를 사용자 예외로 발생시키는 예제
-- ins_emp_proc
CREATE OR REPLACE PROCEDURE 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;
   
    -- (1) 예외 정의 : 잘못된 부서번호
    ex_invalid_depid EXCEPTION;
   
    -- (1) 예외 정의 : 잘못된 입사월
    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
        -- (2) 예외 발생시키기
	    RAISE ex_invalid_depid;
    END IF;
	 
	 -- 입사월 체크 (1~12월 범위를 벗어났는지 체크)
	 IF SUBSTR(p_hire_month, 5, 2) NOT BETWEEN '01' AND '12' THEN
        -- (2) 예외 발생시키기
	    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;              
              
    -- (3) 발생된 예외 처리
    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;
/

-- 프로시저 실행
EXEC ins_emp_proc ('홍길동', 110, '201314');

5

의도적으로 14월의 데이터를 넣을때, 미리 지정해둔 예외처리와 에러코드가 출력됨.






Categories:

Updated:

Leave a comment