(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;
/
오류가 발생하여 프로시저가 실행되지 않는다
- 예외처리 있는 프로시저
-- 예외처리 있는 프로시저
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;
/
예외처리부가 실행되고 프로시저도 실행됨
시스템 예외처리
- 시스템 예외
- 숫자를 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;
시스템 예외처리 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');
jobs 테이블에 해당하는 데이터가 없기 때문에 예외처리문이 수행된다.
사용자 정의 예외처리
사용자 정의 예외
사용자가 직접 예외를 정의해서 사용하는 것
- 사용자 정의 예외를 사용하는 이유
- 예외명이 부여된 것은 시스템 예외 중 극소수
- 이름이 없는 예외에 이름을 부여하면 코드가 훨씬 읽기 편함
- 해당 코드의 로직을 파악하는 것도 쉬워짐
사용자 정의 예외 사용법
- 예외 정의 : 사용자_정의_예외명 EXCEPTION;
- 사용자 예외를 사용하려면 PL/SQL 블록의 선언부에 예외를 정의
- 예외 발생시키기 : RAISE 사용자_정의_예외명;
- 시스템 예외는 자동으로 검출되지만, 사용자 예외는 위의 형태처럼 발생시킴
- 발생된 예외 처리 : 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');
의도적으로 14월의 데이터를 넣을때, 미리 지정해둔 예외처리와 에러코드가 출력됨.
Leave a comment