程序中的例外情况

时间:2018-04-26 00:56:19

标签: oracle

我有如下所示的程序,但是当运行阻止时,如果找不到数据,则不会显示错误消息。

CREATE OR REPLACE 
PROCEDURE DDPROJ_SP
  (P_IDPROJ IN DD_PROJECT.IDPROJ%TYPE,
   P_INFO OUT VARCHAR2,
   p_check OUT VARCHAR2)
IS
  CURSOR cur_ddproj IS
  SELECT *
  FROM   dd_project
  WHERE  idproj = p_idproj;
  lv_projinfo_txt VARCHAR2(100);
BEGIN
  FOR rec_ddproj IN cur_ddproj LOOP
        lv_projinfo_txt := (rec_ddproj.idproj||', '||rec_ddproj.projname||
                           ', '||rec_ddproj.projstartdate||', '||rec_ddproj.                                 projenddate||
                           ', '||rec_ddproj.projfundgoal||', '||rec_ddproj.p                                rojcoord);
  END LOOP;
  P_INFO := LV_PROJINFO_TXT;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
   P_CHECK :='Please select another project';
   DBMS_OUTPUT.PUT_LINE(P_CHECK);
END;

并阻止:

DECLARE
   LV_INFO_TXT VARCHAR2(100);
   LV_CHECK_TXT VARCHAR2(30);
BEGIN
   DDPROJ_SP(00,lv_info_txt,lv_check_txt);
   DBMS_OUTPUT.PUT_LINE(LV_INFO_TXT);
END;

在RUNNING BLOCK之后如果提供的ID是正确的,我会收到请求的信息,但是如果找不到ID,则异常不会在打印时显示消息。

1 个答案:

答案 0 :(得分:3)

首先,正如已经指出的那样,除了调用dbms_output之外,您的异常处理程序不会执行任何真正可见的操作,您只能看到set serverout on或者dbms_output或否则从FOR访问结果。

其次,更重要的是,当您使用NO_DATA_FOUND循环来处理游标的结果时,永远不会引发... end loop; if lv_projinfo_txt is null then raise no_data_found; end if; 异常。

如果您想检测未找到任何行,您可以选择以下几种方法:

  1. 循环后,检查变量是否已设置,例如:

    FOR
  2. 如果您不希望查询找到多于1条记录(由您的谓词建议" id"),则可以避免{{1 }循环并使用简单的select into

    PROCEDURE DDPROJ_SP
      (P_IDPROJ IN DD_PROJECT.IDPROJ%TYPE,
       P_INFO OUT VARCHAR2,
       p_check OUT VARCHAR2)
    IS
    
      rec_ddproj dd_project%rowtype;
    
      lv_projinfo_txt VARCHAR2(100);
    BEGIN
    
      SELECT *
      into   rec_ddproj
      FROM   dd_project
      WHERE  idproj = p_idproj;
    
      lv_projinfo_txt := (rec_ddproj.idproj||',     '||rec_ddproj.projname||
                         ', '||rec_ddproj.projstartdate||', '||rec_ddproj.projenddate||
                         ', '||rec_ddproj.projfundgoal||', '||rec_ddproj.projcoord);
    
      P_INFO := LV_PROJINFO_TXT;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
       P_CHECK :='Please select another project';
       DBMS_OUTPUT.PUT_LINE(P_CHECK);
    END;
    
  3. 注意:

    • select into可能会引发NO_DATA_FOUNDTOO_MANY_ROWS

    • 良好做法是永远不会在不重新引发异常的情况下处理错误,除非您的代码实际处理异常。在您的情况下,您的代码只是通过p_check参数将信号发送回调用进程,该参数将处理错误的责任移交给调用者。在某些情况下这可能没问题,但它假设呼叫者实际上听到了信号。提出一个强制调用者适当处理它的异常会更好。

    • 好的做法是对查询中的所有列和参数进行别名;拥有像idproj = p_idproj这样的SQL谓词可以假设该表将来永远不会有一个名为p_idproj的列。相反,有意识地对所有列和参数进行别名,例如

      ,这是一种好的做法
      SELECT x.*
      into   rec_ddproj
      FROM   dd_project x
      WHERE  x.idproj = ddproj_sp.p_idproj;