繁体   English   中英

哪个命令引发了异常?

[英]Which command raised the exception?

是否存在像SQLERRMSQLCODE这样的变量来保存引发错误的语句?

例:

/* 
if some error raised from this code 
and I want to know which statement cause the failure..
I wish to use some oracle varaible to know it
*/
begin

select * from t1;
select * from t2;

exception when others
 dbms_output.put_line(sqlerrm || ' raised from this statement:' || <some_variable>;
end;

-- excepted result: no data found raised from this statement: select * from t2

简单的答案,不。 通过定义异常处理程序,您将丢失一些信息。 对于未处理的异常,您会收到一条包含行号的错误消息。 但是显然我们需要处理错误,记录错误等。因此,没有行号是很垃圾的。

幸运的是,有两种选择。 在旧版本的Oracle中,我们可以使用dbms_utility.format_error_backtrace()dbms_utility.format_error_stack()获得一些有用的信息,包括行号。 它非常笨拙,并且(特别是用于回溯)非常冗长。

在Oracle 12c中,我们得到了一个专门用于PL / SQL调用堆栈的完整软件包:UTL_CALL_STACK。 它是一盒位,需要多次调用才能得到,但是我们可以使用unit_line()检索特定的行号。 蒂姆·霍尔(Tim Hall)对新功能进行了典型的精美介绍。 了解更多


要考虑的另一件事是良好的程序设计如何解决此问题。 特别是单一责任原则 这是程序设计的基本准则:程序单元应该做一件事。 如果我们问“通过此错误执行哪个命令”的问题,则可能表明我们违反了SRP。

让我们辞职代码,使其遵循以下设计原则:

declare
    type nt1 is table of t1%rowtype;
    type nt2 is table of t2%rowtype;
    l_t1 nt1;
    l_t2 nt2;
    x_t1_ndf exception;
    x_t2_ndf exception;

    function get_t1 return nt1 is
      return_value nt1;
    begin
      select * 
      bulk collect into return_value
      from t1;
      if  return_value.count() = 0 then 
        raise x_t1_ndf;
      end if; 
      return return_value;
  end get_t1;

  function get_t2 return nt2 is
    return_value nt2;
  begin
    select * 
    bulk collect into return_value
    from t2;
    if  return_value.count() = 0 then 
      raise x_t2_ndf;
    end if; 
    return return_value;
  end get_t2;
begin
  l_t1 := get_t1;
  l_t2 := get_t2;
exception 
  when x_t1_ndf then
      dbms_output.put_line('T1 has no data');
  when x_t2_ndf then
      dbms_output.put_line('T2 has no data');
end;

显然,键入的内容比原始代码多,但是部分原因是,此玩具是完整的工作代码,与您发布的代码不同。 同样在现实生活中,这些模块将是离散的单元,而不是匿名块中的私有功能,因此我们可以在其他多个程序中重复使用它们。

dbms_output.put_line()也不是处理异常的正确方法,但是我已经离开了,因为这就是您的代码所做的事情。

没有内置功能可用于此目的。

一种方法是通过处理单个语句的异常,例如(伪代码):

declare
  err varchar2(100);
  myException exception;
begin
  ...

  begin
     select * from t1;
  exception
  when others then
    err := 'Error in select * from t1: ' || sqlerrm;
    raise myException
  end;

  begin
     select * from t2;
  exception
  when others then
    err := 'Error in select * from t2: ' || sqlerrm;
    raise myException
  end;

  ...

exception
 when myException then
  dbms_output.put_line(err);
 when others then
  dbms_output.put_line('Unhandled exception: ' || sqlerrm);
end;

对于更多的东西, 可能非常有用。

对多个语句使用单个异常处理程序总是会掩盖导致错误的语句。

相反,您可以使用Local变量(Locator)来跟踪语句执行,如下所示:

DECLARE
   err_stmt NUMBER:= 1;  -- Indicates 1st SELECT statement
BEGIN
   SELECT ... -- Statement 1
   err_stmt := 2;  -- Indicates 2nd SELECT statement
   SELECT ... -- Statement 2
EXCEPTION 
   WHEN OTHERS THEN
      dbms_output.put_line(sqlerrm || ' raised from this statement number:' || err_stmt;
END;

干杯!!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM