2016年2月7日 星期日

例外 (PL/SQL 三)

※攔截例外


先看一個一定會死的例子
DECLARE 
    i INTEGER;
BEGIN
    i := 10/0;
END;

※結果:
※根據框起來的訊息,去官網找,01476會對應 Error Code ,並把前面的0拿掉,了解後增加如下的程式碼:

DECLARE 
    i INTEGER;
BEGIN
    i := 10/0;
    DBMS_OUTPUT.PUT_LINE('這行印不到');
EXCEPTION
    WHEN ZERO_DIVIDE THEN
        DBMS_OUTPUT.PUT_LINE('被除數不能是0');
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
被除數不能是0 SQLCODE=-1476 SQLERRM=ORA-01476: divisor is equal to zero

※ZERO_DIVEDE是針對這個程式使用的,如果不是這個例外,也就等於沒攔截到,那就是和沒寫是一樣的



DECLARE 
    i INTEGER;
BEGIN
    i := 'S';
    DBMS_OUTPUT.PUT_LINE('這行印不到');
EXCEPTION
    WHEN VALUE_ERROR THEN
        DBMS_OUTPUT.PUT_LINE('給值的型態或長度不正確');
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
給值的型態或長度不正確 SQLCODE=-6502 SQLERRM=ORA-06502: PL/SQL: numeric or value error: character to number conversion error



DECLARE 
    xxx_dname DEPT.DNAME%TYPE;
BEGIN
    SELECT DNAME INTO xxx_dname
    FROM DEPT
    WHERE DEPTNO = 90;
    
    DBMS_OUTPUT.PUT_LINE('這行印不到');
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE('找不到資料');
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
找不到資料 SQLCODE=100 SQLERRM=ORA-01403: no data found

※這個比較奇怪,錯誤的訊息不是100,是「no data found」,剛好裡面也有,所以我照打,還真的攔到了



DECLARE 
    xxx_dname DEPT.DNAME%TYPE;
BEGIN
    SELECT DNAME INTO xxx_dname
    FROM DEPT;
    
    DBMS_OUTPUT.PUT_LINE('這行印不到');
EXCEPTION
    WHEN TOO_MANY_ROWS THEN
        DBMS_OUTPUT.PUT_LINE('找到太多資料');
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
找到太多資料
SQLCODE=-1422
SQLERRM=ORA-01422: exact fetch returns more than requested number of rows

※以上的例子一個一個去查太累了,所以可以用others就一切掉定了,WHEN OTHERS THEN




※自定義例外

※沒有例外的訊息

DECLARE
    i NUMBER;
BEGIN
    DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
    DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
SQLCODE=0
SQLERRM=ORA-0000: normal, successful completion



※宣告例外類型

DECLARE
    i NUMBER := 6;
    xxx_exp EXCEPTION;
BEGIN
    IF i != 4 THEN
        RAISE xxx_exp;
    END IF;
EXCEPTION 
    WHEN xxx_exp THEN
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
SQLCODE=1
SQLERRM=User-Defined Exception

※類型就是EXCEPTION,RAISE和java的throw類似



※自定例外代號

尤於上面的訊息太差了,有和沒有一樣,因為它的代號永遠都是1

DECLARE
    i NUMBER := 6;
    xxx_exp EXCEPTION;
    PRAGMA EXCEPTION_INIT(xxx_exp, -20111);
BEGIN
    IF i != 4 THEN
        RAISE xxx_exp;
    END IF;
EXCEPTION 
    WHEN xxx_exp THEN
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
SQLCODE=-20111
SQLERRM=ORA-20111:

※一定要叫PRAGMA,而自定的錯誤代碼是-20000 ~ -20999,看官網

※如果不是-20000 ~ -20999,例如-01476除零的例外,PRAGMA EXCEPTION_INIT(xxx_exp, -01476);,就會出如下的訊息:
SQLCODE=-1476
SQLERRM=ORA-01476: divisor is equal to zero
就好像變成除零例外的子類



※自定例外訊息

上面的程式碼,雖然解決了例外代號,但訊息仍然有和沒有一樣

DECLARE
    i NUMBER := 6;
    xxx_exp EXCEPTION;
    PRAGMA EXCEPTION_INIT(xxx_exp, -20111);
BEGIN
    IF i != 4 THEN
        RAISE_APPLICATION_ERROR(-20111, '自定義例外');
    END IF;
EXCEPTION 
    WHEN xxx_exp THEN
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※結果:
SQLCODE=-20111
SQLERRM=ORA-20111: 自定義例外

※例用RAISE_APPLICATION_ERROR就可以了,代號要和PRAGMA一樣



※簡化自定義例外訊息

DECLARE
    i NUMBER := 6;
    xxx_exp EXCEPTION;
BEGIN
    IF i != 4 THEN
        RAISE_APPLICATION_ERROR(-20111, '自定義例外');
    END IF;
EXCEPTION 
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('SQLCODE=' || SQLCODE);
        DBMS_OUTPUT.PUT_LINE('SQLERRM=' || SQLERRM);
END;

※也就是省略了PRAGMA EXCEPTION_INIT(xxx_exp, -20111);,而EXCEPTION一定要用OTHERS就可以了,結果和上面的程式碼一樣

沒有留言:

張貼留言