2017-04-20 36 views
2

我注意到TO_TIMESTAMP根據失敗的方式產生了各種錯誤代碼;如何在沒有OTHERS子句的情況下捕獲PLSQL中的TO_TIMESTAMP或TO_DATE異常?

 
--01847 
select to_timestamp('2016-01-0a', 'yyyy-MM-dd') from dual; 
--01858 
select to_timestamp('2016-01-aa', 'yyyy-MM-dd') from dual; 
--01843 
select to_timestamp('2016-15-01', 'yyyy-MM-dd') from dual; 

由於它不會引發一個錯誤代碼,我怎麼能捕獲錯誤,而不訴諸使用包羅萬象的OTHERS

 
DECLARE 
    foo timestamp; 
BEGIN 
    select to_timestamp('2016-01-0a', 'yyyy-MM-dd') into foo from dual; 
EXCEPTION 
    WHEN OTHERS THEN 
     dbms_output.put_line('bad date'); 
END; 
+2

感謝馬修。我想知道你使用的是什麼版本的oracle?如果在12cR2上,如果你有'validate_conversion'函數可能會感興趣。 – alexgibbs

+0

另一個問題,我不知道你的帖子。你是否也想避免多個異常塊(對於不同的異常,多個'EXCEPTION_INIT')或者只是爲了避免'當其他異常'?謝謝 – alexgibbs

+0

@alexgibbs不幸的是我在12cR1,但我們應該遲早會升級,所以我會留意的。理想情況下,除了避免「WHEN OTHERS」之外,對於由不正確的日期字符串導致的'to_timestamp'產生的所有可能的錯誤捕獲單個異常將是很好的,但我不確定這是否可能。 –

回答

2

如果你是12cR2,那麼你可以使用VALIDATE_CONVERSION在進行轉換之前檢查潛在類型轉換的有效性並完全避免該例外。

在早期版本中,您可以爲TIMESTAMP創建自己的等效函數,該函數試圖進行轉換並處理異常。您可以單獨聲明每個異常類型,並根據需要單獨記錄/處理每個感興趣的故障模式,對於您不關心或想要記錄/處理的內容,整體爲WHEN OTHERS

CREATE OR REPLACE FUNCTION IS_TIMESTAMP_FORMAT_OK(P_TIMESTAMP_TEXT IN VARCHAR2, P_FORMAT IN VARCHAR2 DEFAULT 'yyyy-MM-dd') 
    RETURN BOOLEAN 
IS 
    --exception names 
    V_TIMESTAMP TIMESTAMP; 
    DAY_OF_MONTH EXCEPTION; 
    NON_NUMERIC EXCEPTION; 
    --etc. 
PRAGMA EXCEPTION_INIT (DAY_OF_MONTH, -1847); 
PRAGMA EXCEPTION_INIT (NON_NUMERIC, -1858); 
    BEGIN 
    V_TIMESTAMP := to_timestamp(P_TIMESTAMP_TEXT, P_FORMAT); 
    RETURN TRUE; 
    EXCEPTION WHEN DAY_OF_MONTH 
    THEN 
    DBMS_OUTPUT.PUT_LINE('The day of month must be between...'); 
    RETURN FALSE; 
    WHEN NON_NUMERIC 
    THEN 
    DBMS_OUTPUT.PUT_LINE('Non-Numeric data was found...'); 
    RETURN FALSE; 
    --etc. 
    WHEN OTHERS THEN 
    DBMS_OUTPUT.PUT_LINE(UTL_LMS.FORMAT_MESSAGE('Unexpected timestamp problem: %s', SQLERRM)); 
    RETURN FALSE; 
    END; 
/

然後你就可以登錄/處理類型的興趣:

DECLARE 
    V_CHECK BOOLEAN; 
BEGIN 
    V_CHECK := IS_TIMESTAMP_FORMAT_OK('2016010a'); 
    V_CHECK := IS_TIMESTAMP_FORMAT_OK('2016-01-aa'); 
    V_CHECK := IS_TIMESTAMP_FORMAT_OK('2016-01-0a'); 
    IF IS_TIMESTAMP_FORMAT_OK('2014-01-01') 
    THEN 
    DBMS_OUTPUT.PUT_LINE('It is ok. Yay'); 
    END IF; 
END; 
/

Unexpected timestamp problem: ORA-01862: the numeric value does not match the 
length of the format item 
Non-Numeric data was found... 
The day of month must be between... 
It is ok. Yay 

或者,如果你不關心日誌記錄/處理不同故障模式,只是想阻止廣泛的異常奪目,你可以繼續使用WHEN OTHERS,但在隔離範圍內:

CREATE OR REPLACE FUNCTION 
    IS_TIMESTAMP_FORMAT_OK(P_TIMESTAMP_TEXT IN VARCHAR2, P_FORMAT IN VARCHAR2 DEFAULT 'yyyy-MM-dd') 
    RETURN BOOLEAN 
IS 
    V_TIMESTAMP TIMESTAMP; 
    BEGIN 
    V_TIMESTAMP := to_timestamp(P_TIMESTAMP_TEXT, P_FORMAT); 
    RETURN TRUE; 
    EXCEPTION WHEN OTHERS THEN 
    RETURN FALSE; 
    END; 
/

或內聯:

DECLARE 
    V_MY_TIMESTAMP TIMESTAMP; 
    BEGIN 
    -- some other code ... 

    BEGIN 
    V_MY_TIMESTAMP := to_timestamp('2016-01-aa', 'yyyy-MM-dd'); 
    EXCEPTION WHEN OTHERS THEN NULL; 
    END; 

    DBMS_OUTPUT.PUT_LINE('My Timestamp:'||V_MY_TIMESTAMP); 

END; 
/

My Timestamp: 
+0

謝謝。我可能只需要解決在獨立範圍內使用「WHEN OTHERS」的建議,直到我們可以升級到12cR2。您是否想知道在哪裏可以找到to_timestamp引發的所有可能的錯誤代碼的列表,以防我想嘗試全面的路由? –

+0

謝謝@MatthewMoisen。我之前沒有遇到過時間戳轉換異常的完整列表。這是一個很好的問題;如果你能找到它,我會非常感興趣的。實際上,可拋異常的綜合列表似乎對大多數Oracle提供的函數具有實用性。請讓我知道,如果你發現什麼好。謝謝 – alexgibbs

+0

1+使用'UTL_LMS.FORMAT_MESSAGE' –

相關問題