如何在没有OTHERS子句的情况下捕获PLSQL中的TO_TIMESTAMP或TO_DATE异常?

时间:2017-04-20 21:55:07

标签: oracle plsql

我注意到TO_TIMESTAMP根据失败的原因引发了各种错误代码;

--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;

1 个答案:

答案 0 :(得分: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: