Oracle 不捕获异常

Oracle Doesn't Catch Exception

我在 Oracle 中有一个过程,我遇到了一个错误,但它没有更改 p_out_msg 的值,为什么会这样??错误转到光标处。

代码:

PROCEDURE get_proj(p_date    IN VARCHAR2,
                   p_out_cur OUT sys_refcursor,
                   p_out_msg OUT VARCHAR2)
IS 
BEGIN
  OPEN p_out_cur FOR 
    SELECT *
      FROM table t
     WHERE TO_DATE(p_date, 'DD-MM-YYYY HH24:MI:SS') = t.date

  p_out_msg := 'SUCCESS';

EXCEPTION
   WHEN OTHERS THEN
     p_out_msg := SUBSTR('An error was encountered: '||SQLERRM, 1, 250);

END get_proj;

假设我输入了无效日期:

输出:

p_out_cur: ORA-01858: a non-numeric character was found where a numeric was expected

p_out_msg: SUCCESS

这是@brenners1302请求的匿名块:

DECLARE
  P_DATE VARCHAR2(200);
  P_OUT_CUR sys_refcursor;
  P_OUT_MSG VARCHAR2(200);
BEGIN
  P_DATE := '1111';

  PACKAGE_TEST.GET_PROJ(
    P_DATE => P_DATE,
    P_OUT_CUR => P_OUT_CUR,
    P_OUT_MSG => P_OUT_MSG
  );

  DBMS_OUTPUT.PUT_LINE(P_OUT_MSG); --SUCCESS

END;

当您使用 OPEN p_out_cur FOR 打开游标时,查询 SELECT * FROM ... 此刻并未执行,而只是与游标变量相关联。所以当你从p_out_cur开始FETCH时可能会出现异常,因为这是关联查询开始执行的时候。

查看它的最简单方法是以这种方式更改您的程序。

PROCEDURE get_proj(p_date    IN VARCHAR2,
                   p_out_cur OUT sys_refcursor,
                   p_out_msg OUT VARCHAR2)
IS 
 l_rec myTable%ROWTYPE;
BEGIN
       OPEN p_out_cur FOR 
        SELECT *
          FROM myTable t
         WHERE TO_DATE(p_date, 'DD-MM-YYYY HH24:MI:SS') = t.date

      -- at this point we can get an exception
      FETCH p_out_cur INTO l_rec;

      p_out_msg := 'SUCCESS';

EXCEPTION
   WHEN OTHERS THEN
       p_out_msg := SUBSTR('An error was encountered: '||SQLERRM, 1, 250);    
END get_proj;

所以是的,这意味着当您打开一个引用游标并将其传递给 'outer world' 时,试图获取它的人可能会遇到异常。在将参数传递给与游标关联的 SQL 中使用的函数之前,您可以通过检查参数来减少此类情况的数量。例如,

PROCEDURE get_proj(p_date    IN VARCHAR2,
               p_out_cur OUT sys_refcursor,
               p_out_msg OUT VARCHAR2)
IS 
 l_normal_date DATE;
BEGIN
       -- if p_date has wrong format we better find it out
       -- before using it in a query
       l_normal_date := TO_DATE(p_date, 'DD-MM-YYYY HH24:MI:SS');

       OPEN p_out_cur FOR 
        SELECT *
          FROM myTable t
         WHERE l_normal_date = t.date

      p_out_msg := 'SUCCESS';

EXCEPTION
   WHEN OTHERS THEN
       p_out_msg := SUBSTR('An error was encountered: '||SQLERRM, 1, 250);    
END get_proj;