存储过程未返回预期的自定义异常消息

Posted

技术标签:

【中文标题】存储过程未返回预期的自定义异常消息【英文标题】:Stored procedure is not returning expected custom exception message 【发布时间】:2019-01-05 11:21:53 【问题描述】:

我正在使用这个存储过程,我在其中检查游标是否包含任何数据,如果它有 0 条记录,则引发异常,否则将数据返回到输出中。

CREATE OR replace PROCEDURE user_details(v_ownerid    IN NUMBER, 
                                             v_branchcode IN NVARCHAR2, 
                                             v_login      IN NVARCHAR2, 
                                             cv_1         OUT SYS_REFCURSOR) 
IS 
  result_out1   SYS_REFCURSOR; 
  v_territoryid NUMBER(10); 
  v_user        NUMBER(10); 
  CURSOR cc IS 
    SELECT Z.username AS USERNAME, 
           Z.loginid  AS LOGINID, 
           Z.userid   AS CRMUSERID 
    FROM   userterritory U 
           inner join teammembers T 
                   ON U.ownerid = T.ownerid 
                      AND U.userid = T.memberid 
           inner join az_user Z 
                   ON Z.appownerid = T.ownerid 
                      AND Z.userid = T.memberid; 
  TYPE tbl_join 
    IS TABLE OF cc%ROWTYPE; 
  l_table       TBL_JOIN; 
BEGIN 
    SELECT regionid 
    INTO   v_territoryid 
    FROM   regions 
    WHERE  ownerid = v_ownerid 
           AND categorytype = 3 
           AND code = v_branchcode; 

    SELECT userid 
    INTO   v_user 
    FROM   az_user 
    WHERE  appownerid = v_ownerid 
           AND loginid = v_login; 

    OPEN result_out1 FOR 
      SELECT Z.username AS USERNAME, 
             Z.loginid  AS LOGINID, 
             Z.userid   AS CRMUSERID 
      FROM   userterritory U 
             inner join teammembers T 
                     ON U.ownerid = T.ownerid 
                        AND U.userid = T.memberid 
             inner join az_user Z 
                     ON Z.appownerid = T.ownerid 
                        AND Z.userid = T.memberid 
      WHERE  Z.appownerid = v_ownerid 
             AND T.reportsto = v_user 
             AND U.territoryid = v_territoryid; --using whereClause;      
    FETCH result_out1 bulk collect INTO l_table; 

--    FETCH result_out1 bulk collect INTO l_table; 

    dbms_output.Put_line('Count ' 
                         || l_table.count); 

    IF l_table.count > 0 THEN 
      OPEN cv_1 FOR 
        SELECT Z.username AS USERNAME, 
               Z.loginid  AS LOGINID, 
               Z.userid   AS CRMUSERID 
        FROM   userterritory U 
               inner join teammembers T 
                       ON U.ownerid = T.ownerid 
                          AND U.userid = T.memberid 
               inner join az_user Z 
                       ON Z.appownerid = T.ownerid 
                          AND Z.userid = T.memberid 
        WHERE  Z.appownerid = v_ownerid 
               AND T.reportsto = v_user 
               AND U.territoryid = v_territoryid; 
    ELSE 
      Raise_application_error(-20001, 'Data Not Found.'); 
    END IF; 
END; 

如果数据不存在,此存储过程将引发异常。但不是返回自定义异常消息,而是返回系统异常:

ORA-01403:未找到数据

我在这里做错了吗?是否需要进行任何更改才能返回自定义异常消息,即“未找到数据”?我将修改此消息。早些时候我在 SP 下使用,但在记录为 0 的情况下它没有返回任何错误消息,因为我已经完成了存储过程中提到的更改:

CREATE OR replace PROCEDURE user_details(v_ownerid    IN NUMBER, 
                                             v_branchcode IN NVARCHAR2, 
                                             v_login      IN NVARCHAR2, 
                                             cv_1         OUT SYS_REFCURSOR) 
AS 
  v_territoryid NUMBER(10); 
  v_user        NUMBER(10); 
BEGIN 
    SELECT regionid 
    INTO   v_territoryid 
    FROM   regions 
    WHERE  ownerid = v_ownerid 
           AND categorytype = 3 
           AND code = v_branchcode; 

    SELECT userid 
    INTO   v_user 
    FROM   az_user 
    WHERE  appownerid = v_ownerid 
           AND loginid = v_login; 

    OPEN cv_1 FOR 
      SELECT Z.username AS USERNAME, 
             Z.loginid  AS LOGINID, 
             Z.userid   AS CRMUSERID 
      FROM   userterritory U 
             inner join teammembers T 
                     ON U.ownerid = T.ownerid 
                        AND U.userid = T.memberid 
             inner join az_user Z 
                     ON Z.appownerid = T.ownerid 
                        AND Z.userid = T.memberid 
      WHERE  Z.appownerid = v_ownerid 
             AND T.reportsto = v_user 
             AND U.territoryid = v_territoryid; 
END; 

【问题讨论】:

我怀疑其中一个 pure 选择(select useridselect regionid)返回 ORA-01403,而不是光标。 错误可能来自SELECT regionid INTO v_territoryid FROM regionsSELECT userid INTO v_user @KaushikNayak 和 Littlefoot 谢谢。我错过了检查那部分是我的错误。是的,该行发生了异常。我已经评论了那部分以供检查。它正在返回预期的错误消息。 【参考方案1】:

ORA-01403: no data found 是从 BULK COLLECT 之前的两个 select 语句中的任何一个引发的,来自 CURSOR

除此之外,您的代码似乎包含几个冗余结构,使其变得不必要地复杂。例如,CURSOR cc 的唯一目的是定义该类型的表变量,如果您的意图只是在打开游标之前检查记录是否存在,则不需要使用 BULK COLLECT

你可以这样重写。

CREATE OR replace PROCEDURE user_details (v_ownerid    IN NUMBER, 
                                          v_branchcode IN NVARCHAR2, 
                                          v_login      IN NVARCHAR2, 
                                          cv_1         OUT SYS_REFCURSOR) 
IS 
  v_territoryid NUMBER(10); 
  v_user        NUMBER(10); 
  l_count       INT; 
BEGIN 
    SELECT regionid 
    INTO   v_territoryid 
    FROM   regions 
    WHERE  ownerid = v_ownerid 
           AND categorytype = 3 
           AND code = v_branchcode; 

    SELECT userid 
    INTO   v_user 
    FROM   az_user 
    WHERE  appownerid = v_ownerid 
           AND loginid = v_login; 

    SELECT CASE 
             WHEN EXISTS (SELECT 1  --check if a row exists.
                          FROM   userterritory u 
                                 INNER JOIN teammembers t 
                                         ON u.ownerid = t.ownerid 
                                            AND u.userid = t.memberid 
                                 INNER JOIN az_user z 
                                         ON z.appownerid = t.ownerid 
                                            AND z.userid = t.memberid 
                          WHERE  z.appownerid = v_ownerid 
                                 AND t.reportsto = v_user 
                                 AND u.territoryid = v_territoryid) THEN 1 
             ELSE 0 
           END 
    INTO   l_count 
    FROM   dual; 

    IF l_count = 1 THEN 
      OPEN cv_1 FOR 
        SELECT z.username AS username, 
               z.loginid  AS loginid, 
               z.userid   AS crmuserid 
        FROM   userterritory u 
               INNER JOIN teammembers t 
                       ON u.ownerid = t.ownerid 
                          AND u.userid = t.memberid 
               INNER JOIN az_user z 
                       ON z.appownerid = t.ownerid 
                          AND z.userid = t.memberid 
        WHERE  z.appownerid = v_ownerid 
               AND t.reportsto = v_user 
               AND u.territoryid = v_territoryid; 
    ELSE 
      raise_application_error(-20001, 'Data Not Found.'); 
    END IF; 
EXCEPTION 
  WHEN no_data_found THEN 
             raise_application_error(-20001, 'regionid or userid not Found.'); 
        -- Handling the exception  
        --for errors from first 2 selects 
END; 
/ 

【讨论】:

以上是关于存储过程未返回预期的自定义异常消息的主要内容,如果未能解决你的问题,请参考以下文章

用于检索自定义消息而不是异常详细信息的 PLSQL 异常处理

带有错误代码和错误消息的自定义 Python 异常

Spring Security:来自 UserDetailsS​​ervice 的自定义异常消息

如何使用 JAX-RS 异常上的自定义消息设置 40X 错误?

Java中的自定义异常捕获方式

从服务器抛出的自定义错误未在客户端的 HttpErrorResponse 中返回