Data Base/PL SQL

231031 PL/SQL EXCEPTION(예외처리)

잇꼬 2023. 10. 31. 17:11
728x90
반응형
SMALL

■ exception (예외처리)

1. 실행 중에 발생한 PL/SQL 오류

2. Oracle에 의해서 암시적으로 발생.

3. 프로그램에 의해서 명시적으로 발생. 

 

DECLARE 
    v_id NUMBER := 300;
    v_rec hr.employees%rowtype;
BEGIN
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE employee_id = v_id;
    
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);
END;
/

 

# 예외 처리 

DECLARE 
    v_id NUMBER := 300;
    v_rec hr.employees%rowtype;
BEGIN
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE employee_id = v_id; --오류발생 'NO_DATA_FOUND'
    
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

EXCEPTION --예외처리
    WHEN NO_DATA_FOUND/*오류명*/ THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
END;
/

# 예외처리할 경우, 오류명으로만 작성할 것.

DECLARE 
    v_id NUMBER := 20;
    v_rec hr.employees%rowtype;
BEGIN
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE department_id = v_id;
    
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

EXCEPTION --예외처리
    WHEN NO_DATA_FOUND/* 오류명으로만 가능, 오류번호X 오류메시지X*/ THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
    WHEN TOO_MANY_ROWS THEN
        dbms_output.put_line(v_id||' 부서 사원들은 여러명입니다. 명시적인 커서를 이용해주세요.');
END;
/

 

# 첫 번째 예외처리가 거쳐가지 않으면, 'others'로 넘어간다. 

(작성하는 것은 필수X)

DECLARE 
    v_id NUMBER := 20;
    v_rec hr.employees%rowtype;
BEGIN
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE department_id = v_id;
    
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

EXCEPTION --예외처리
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
    WHEN OTHERS THEN -- 필수X 
        dbms_output.put_line('오류가 발생했습니다.');
END;
/

 

# 오류코드, 오류메시지 출력

DECLARE 
    v_id NUMBER := 20;
    v_rec hr.employees%rowtype;
BEGIN
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE department_id = v_id;
    
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

EXCEPTION --예외처리
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
    WHEN OTHERS THEN 
        dbms_output.put_line(SQLCODE); -- 오류코드
        dbms_output.put_line(SQLERRM); -- 오류메시지
END;
/

 

# 연습

DECLARE 
    v_id NUMBER := 300;
    v_rec hr.employees%rowtype;
BEGIN
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE employee_id = v_id;
    
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

EXCEPTION --예외처리
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
    WHEN OTHERS THEN 
        dbms_output.put_line(SQLCODE); -- 오류코드
        dbms_output.put_line(SQLERRM); -- 오류메시지
END;
/

 

# 동일한 오류명으로 여러 코드를 작성하면 오류나니, 단 한번만 작성 할 것.

DECLARE 
    v_id NUMBER := 300;
    v_rec hr.employees%rowtype;
BEGIN
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE employee_id = v_id;
    
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

EXCEPTION --예외처리
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
    WHEN OTHERS THEN 
        dbms_output.put_line(SQLCODE); -- 오류코드
        dbms_output.put_line(SQLERRM); -- 오류메시지
END;
/

#  프로그램이 비상적인 종료가 수행되면 transaction 은 자동 ROLLBACK 된다. (기본)

DECLARE 
    v_rec hr.employees%rowtype;
BEGIN
    UPDATE hr.employees
    SET salary = salary*1.1
    WHERE department_id = 20; -- Transaction 발생+진행중인 상태
    
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE department_id = 20; -- 오류발생
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

END;
/

# 예외처리

1. 프로그램 내에서 오류발생 했으나, 그 오류에 따른 예외사항 처리를 수행하면 transaction 은 살아 있고 진행중인 상태. 

2. 꼭 프로그램 내에서 transaction 을 종료(COMMIT, ROLLBACK) 할지, 프로그램외 에서 할지 결정해야 함.

 

SELECT salary FROM hr.employees WHERE department_id = 20;
DECLARE 
    v_rec hr.employees%rowtype;
BEGIN
    UPDATE hr.employees
    SET salary = salary*1.1
    WHERE department_id = 20; -- Transaction 발생+진행중인 상태
    
    SELECT *
    INTO v_rec
    FROM hr.employees
    WHERE department_id = 20; -- 오류발생
    dbms_output.put_line(v_rec.employee_id||' '||v_rec.last_name);

EXCEPTION --예외처리
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_rec.employee_id||' 사원은 존재하지 않습니다.');
    WHEN OTHERS THEN 
        dbms_output.put_line(SQLCODE); -- 오류코드
        dbms_output.put_line(SQLERRM); -- 오류메시지

END;
/

 

# 확

SELECT  * 
FROM user_constraints
WHERE table_name IN ('EMPLOYEES', 'DEPARTMENTS');

SELECT  * 
FROM user_cons_columns
WHERE table_name IN ('EMPLOYEES', 'DEPARTMENTS');

 

오류: integrity constraint (HR.EMP_DEPT_FK) violated - child record found

DELETE FROM hr.departments WHERE department_id = 20;

# 예외처리 

- ORA-02292: integrity constraint (HR.EMP_DEPT_FK) violated - child record found

- 오류명이 없이 예외상항처리가 어렵다. 이럴 경우에는 오류명USER가 지정해 주면 된다.

BEGIN
    DELETE FROM hr.departments WHERE department_id = 20;
EXCEPTION
    WHEN OTHERS THEN
        dbms_output.put_line(SQLCODE); -- 오류코드
        dbms_output.put_line(SQLERRM); -- 오류메시지
END;
/

 

# 오라클의 오류번호와 예외사항 이름을 붙이는 작업(오류명이 없는 경우) 

- 예외처리: 변수처리 및 지정

- DECLARE 에서 예외변수 선언시, PRAGMA EXCEPTION_INIT(오류명 변수, 오류번호);

DECLARE
    pk_error EXCEPTION; -- 예외사항 이름 선언
    PRAGMA EXCEPTION_INIT(pk_error, -2292); -- 예외사항 변수 지정, 오류번호(음수) 지정
BEGIN
    DELETE FROM hr.departments WHERE department_id = 20;
EXCEPTION
    WHEN pk_error THEN
        dbms_output.put_line('이 값을 참조하고 있는 행들이 있습니다.');
    WHEN OTHERS THEN
        dbms_output.put_line(SQLCODE); -- 오류코드
        dbms_output.put_line(SQLERRM); -- 오류메시지
END;
/

# 예외처리를 EXCEPTION 에서 처리하지 않는 방법

BEGIN
    UPDATE hr.employees
    SET salary = salary*1.1
    WHERE employee_id = 300;
    
    IF sql%notfound THEN
        dbms_output.put_line('영향을 받은 행이 없습니다.');
    END IF;

END;
/

# 사용자가 정의한 예외사항( ex) 업무, 감사 )

DECLARE
    e_invalid EXCEPTION; -- 오류명 선언
BEGIN
    UPDATE hr.employees
    SET salary = salary*1.1
    WHERE employee_id = 300;
    
    IF sql%notfound THEN
        RAISE e_invalid; -- RAISE 오류명 : 무조건 EXCEPTION절 로 실행.
    END IF;

EXCEPTION
    WHEN e_invalid THEN
        dbms_output.put_line('영향을 받은 행이 없습니다.');    
END;
/

# 특정 data 를 조회 안되게 하는 방법

- IF문 + RAISE 을 활용하자!

    v_name VARCHAR2(30);
    v_dept_name VARCHAR2(30);
    
    emp_raise EXCEPTION;

BEGIN
    
    IF v_id  = 100 THEN
        RAISE emp_raise;
    END IF;
    
    SELECT e.last_name, d.department_name
    INTO v_name, v_dept_name
    FROM hr.employees e, hr.departments d 
    WHERE e.department_id = d.department_id
    AND e.employee_id = v_id;
    
    dbms_output.put_line(v_name||' '||v_dept_name);
    
EXCEPTION
    WHEN emp_raise THEN
        dbms_output.put_line(v_id||' 사원은 조회할 수 없습니다');
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
END;
/

 

# user 가 정의한 오류가 발생할 수 있는 프로시저, 프로그램은 비정상적인 종료

# RAISE_APPLICATION_ERROR(오류번호, 오류메시지, FALSE);

1. 오류번호 : -20000 ~ -20999

2. TRUE : 오라클의 오류와 user가 만든 오류가 같이 출력

3. FALSE : 기본값, user가 만든 오류만 출력, 생략 가능

DECLARE
    v_id NUMBER := 100; 
    v_name VARCHAR2(30);
    v_dept_name VARCHAR2(30);
    
BEGIN
    IF v_id  = 100 THEN
        RAISE_APPLICATION_ERROR(-20000, '조회할 수 없습니다.');
    END IF;
    
    SELECT e.last_name, d.department_name
    INTO v_name, v_dept_name
    FROM hr.employees e, hr.departments d 
    WHERE e.department_id = d.department_id
    AND e.employee_id = v_id;
    
    dbms_output.put_line(v_name||' '||v_dept_name);
    
EXCEPTION
    WHEN NO_DATA_FOUND THEN 
        dbms_output.put_line(v_id||' 사원은 존재하지 않습니다.');
END;
/

 

# 오류번호, 오류메시지 변경(비정상적인 종료)

DECLARE
    v_id NUMBER := 300; 
    v_name VARCHAR2(30);
    v_dept_name VARCHAR2(30);
    
BEGIN
    IF v_id  = 100 THEN
        RAISE_APPLICATION_ERROR(-20000, '조회할 수 없다.');
    END IF;
    
    SELECT e.last_name, d.department_name
    INTO v_name, v_dept_name
    FROM hr.employees e, hr.departments d 
    WHERE e.department_id = d.department_id
    AND e.employee_id = v_id;
    
    dbms_output.put_line(v_name||' '||v_dept_name);
    
EXCEPTION
    WHEN NO_DATA_FOUND THEN 
        RAISE_APPLICATION_ERROR(-20001, '조회된 데이터가 없습니다.');
END;
/

 

# RAISE_APPLICATION_ERRE(오류번호, '오류메시지', TRUE); = 기존 오류번호, 오류메시지 도 같이 출력

DECLARE
    v_id NUMBER := 300; 
    v_name VARCHAR2(30);
    v_dept_name VARCHAR2(30);
    
BEGIN
    IF v_id  = 100 THEN
        RAISE_APPLICATION_ERROR(-20000, '조회할 수 없다.');
    END IF;
    
    SELECT e.last_name, d.department_name
    INTO v_name, v_dept_name
    FROM hr.employees e, hr.departments d 
    WHERE e.department_id = d.department_id
    AND e.employee_id = v_id;
    
    dbms_output.put_line(v_name||' '||v_dept_name);
    
EXCEPTION
    WHEN NO_DATA_FOUND THEN 
        RAISE_APPLICATION_ERROR(-20001, '조회된 데이터가 없습니다.', TRUE);
END;
/

 

 

728x90
반응형
LIST