簡體   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