사용자 정의 예외
지금까지 시스템 예외에 대해 살펴 봤는데, 사용자 즉 개발자가 직접 예외를 정의해서 사용할 때가 있을 수 있다. 예컨대 사원 테이블에 신규 사원을 입력하는 프로시저를 작성한다고 해 보자. 이 프로시저는 사원명, 급여, 부서번호 등를 매개변수로 전달받아야 한다(사번은 기존 사번의 최댓값+1, 입사일자는 현재일자를 입력하면 굳이 매개변수로 받지 않아도 입력 가능하다). 그런데 부서 테이블에 없는 부서번호를 전달받았다고 한다면 어떻게 될까? 시스템 내부적으로는 오류가 발생하지 않는다. 왜냐하면 오라클은 부서 테이블에 해당 부서번호의 존재유무를 체크해야 한다는 사실을 알지 못하기 때문이다. 이런 경우에는 다음과 같이 사용자가 직접 처리해 줘야 한다.
입력
...
...
SELECT COUNT(*)
INTO vn_cnt
FROM DEPARTMENTS
WHERE DEPARTMENT_ID = P_DEPARTMENT_ID;
IF vn_cnt = 0 THEN
DBMS_OUTPUT.PUT_LINE('해당 부서번호가 없습니다');
RETURN;
END IF;
...
...
위와 같이 처리해도 무방하지만, 이런 형태의 비즈니스 로직에 따른 예외처리도 오라클 시스템 예외처럼 다룰 수 있다(이전 절에서 사원 테이블의 job_id를 갱신하는 ch10_upd_jobid_proc 프로시저처럼 NO_DATA_FOUND 시스템 예외로 처리할 수도 있지만, 위 코드는 사용자 정의 예외 사용법을 학습하려는 목적으로 IF문 형태로 사용한 것이다).즉 사용자가 직접 예외를 정의하고 해당 예외가 발생하면 EXCEPTION절에서 처리할 수 있다. 사용자 예외 사용법은 다음과 같다.
① 예외 정의: 사용자_정의_예외명 EXCEPTION;
사용자 예외를 사용하려면 일단 변수나 상수처럼 PL/SQL 블록의 선언부에 예외를 정의해야 한다.
② 예외 발생시키기: RAISE 사용자_정의_예외명;
시스템 예외는 해당 예외가 자동으로 검출되지만, 사용자 정의 예외는 직접 예외를 발생시켜야 하는데, “RAISE 예외명;” 형태로 사용한다.
③ 발생된 예외 처리: EXCEPTION WHEN 사용자_정의_예외명 THEN ….
예외를 발생시키면 자동으로 제어권이 EXCEPTION 절로 넘어오므로 시스템 예외와 동일한 방식으로 처리해 주면 된다.
그럼 신규사원을 입력하는데 부서번호가 잘못 들어온 경우를 처리하는 예외 로직이 담긴 프로시저를 만들어 보자.
입력
CREATE OR REPLACE PROCEDURE ch10_ins_emp_proc (
p_emp_name employees.emp_name%TYPE,
p_department_id departments.department_id%TYPE )
IS
vn_employee_id employees.employee_id%TYPE;
vd_curr_date DATE := SYSDATE;
vn_cnt NUMBER := 0;
ex_invalid_depid EXCEPTION; -- 잘못된 부서번호일 경우 예외 선언
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;
-- 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, vd_curr_date, p_department_id );
COMMIT;
EXCEPTION
WHEN ex_invalid_depid THEN -- 사용자 정의 예외 처리
DBMS_OUTPUT.PUT_LINE('해당 부서번호가 없습니다');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
결과
PROCEDURE CH10_INS_EMP_PROC이(가) 컴파일되었습니다.
이제 잘못된 부서번호를 넘겨 프로시저를 실행해 보자.
입력
EXEC ch10_ins_emp_proc ('홍길동', 999);
결과
해당 부서번호가 없습니다
원하던 대로 결과가 출력되었다. 이렇게 비즈니스 로직 상 예외처리해야 할 부분에서 사용자 정의 예외를 사용하면 해당 예외처리 로직의 가독성을 향상시켜 유지, 관리하기가 훨씬 쉽다.