是否存在像SQLERRM
或SQLCODE
这样的变量来保存引发错误的语句?
示例:
/*
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
答案 0 :(得分:5)
简单的答案,不。通过定义异常处理程序,您将丢失一些信息。对于未处理的异常,您会收到一条包含行号的错误消息。但是显然我们需要处理错误,记录错误等。因此,没有行号是很垃圾的。
幸运的是,有两种选择。在旧版本的Oracle中,我们可以使用dbms_utility.format_error_backtrace()
和dbms_utility.format_error_stack()
来获取一些有用的信息,包括行号。这非常笨拙,并且(特别是用于回溯)很冗长。
在Oracle 12c中,我们得到了一个专用于PL / SQL调用堆栈的完整软件包:UTL_CALL_STACK。它是一盒位,需要多次调用才能得到结果,但是我们可以使用unit_line()
来检索特定的行号。蒂姆·霍尔(Tim Hall)对新功能进行了典型的精美介绍。 Find out more。
要考虑的另一件事是好的程序设计如何解决此问题。具体是the Single Responsibility Principle。这是程序设计的基本准则:程序单元应该做一件事。如果我们问“通过此错误执行哪个命令”问题,则可能表明我们违反了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()
也不是处理异常的正确方法,但是我已经离开了,因为这正是您的代码所要做的。
答案 1 :(得分:0)
没有内置功能可用于此目的。
一种方法可能是通过处理单个语句的异常,例如(伪代码):
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;
更多内容,this可能非常有用。
答案 2 :(得分:0)
为多个语句使用单个异常处理程序始终会屏蔽 导致错误的语句。
相反,您可以使用局部变量(定位符)来跟踪语句执行,如下所示:
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;
干杯!