我正在编写一个脚本来执行多个唯一查询(不能放在循环中)。添加异常处理程序时,一旦发生第一个错误,便会处理异常,但编译器会退出该块并终止程序。
如何让我的程序处理异常并继续执行下一个查询?
下面是我一直在处理的代码:
DECLARE
NEW_VAR1 VARCHAR2(20000);
table_does_not_exist exception;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
BEGIN
DBMS_output.put_line('Query 1 Execution');
EXECUTE IMMEDIATE 'BEGIN
SELECT "defaultpwd" INTO :out1 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
END;'
USING out NEW_VAR1;
DBMS_output.put_line(NEW_VAR1);
DBMS_output.put_line('Query 2 Execution');
EXECUTE IMMEDIATE 'BEGIN
SELECT "defaultpwd" INTO :out2 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
END;'
USING out NEW_VAR1;
DBMS_output.put_line(NEW_VAR1);
EXCEPTION
WHEN table_does_not_exist THEN
DBMS_output.put_line('Table does not exist!!');
WHEN others then
DBMS_output.put_line('Error!!');
END;
在这种情况下所需的结果将是:
Query 1 Execution
Error!!
Query 2 Execution
Error!!
实际结果是:
Query 1 Execution
Error!!
如果上述代码效率不高,我可以选择执行多种不同查询的替代方法。
答案 0 :(得分:2)
我认为您需要为每个查询使用不同的异常块。像这样:
DECLARE
NEW_VAR1 VARCHAR2(20000);
table_does_not_exist exception;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
BEGIN
BEGIN
DBMS_output.put_line('Query 1 Execution');
EXECUTE IMMEDIATE 'BEGIN
SELECT "defaultpwd" INTO :out1 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
END;'
USING out NEW_VAR1;
DBMS_output.put_line(NEW_VAR1);
EXCEPTION
WHEN table_does_not_exist THEN
DBMS_output.put_line('Table does not exist!!');
WHEN others then
DBMS_output.put_line('Error!!');
END;
BEGIN
DBMS_output.put_line('Query 2 Execution');
EXECUTE IMMEDIATE 'BEGIN
SELECT "defaultpwd" INTO :out2 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
END;'
USING out NEW_VAR1;
DBMS_output.put_line(NEW_VAR1);
EXCEPTION
WHEN table_does_not_exist THEN
DBMS_output.put_line('Table does not exist!!');
WHEN others then
DBMS_output.put_line('Error!!');
END;
END;
答案 1 :(得分:1)
原则上,您必须这样做:
DECLARE
NEW_VAR1 VARCHAR2(20000);
table_does_not_exist exception;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
BEGIN
BEGIN
DBMS_output.put_line('Query 1 Execution');
EXECUTE IMMEDIATE 'BEGIN
SELECT "defaultpwd" INTO :out1 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
END;'
USING out NEW_VAR1;
DBMS_output.put_line(NEW_VAR1);
EXCEPTION
WHEN table_does_not_exist THEN
DBMS_output.put_line('Table does not exist!!');
WHEN others then
DBMS_output.put_line('Error!!');
END;
BEGIN
DBMS_output.put_line('Query 2 Execution');
EXECUTE IMMEDIATE 'BEGIN
SELECT "defaultpwd" INTO :out2 from sys.user$ where name="APEX_040000" and substr(spare4,3,40)=rawtohex(utl_raw.cast_to_varchar2(sys.dbms_crypto.hash(utl_raw.cast_to_raw("oracle")||hextoraw(substr(spare4,43,20)), 3))) UNION SELECT "defaultpwd" from sys.user$ where name="APEX_040000" and password="EE7785338B8FFE3D";
END;'
USING out NEW_VAR1;
DBMS_output.put_line(NEW_VAR1);
EXCEPTION
WHEN table_does_not_exist THEN
DBMS_output.put_line('Table does not exist!!');
WHEN others then
DBMS_output.put_line('Error!!');
END;
END;
或将其放在循环中:
BEGIN
FOR i IN 1..2 LOOP
BEGIN
DBMS_output.put_line('Query '||i||' Execution');
EXECUTE IMMEDIATE ...
EXCEPTION
WHEN table_does_not_exist THEN
DBMS_output.put_line('Table does not exist!!');
WHEN others then
DBMS_output.put_line('Error!!');
END;
END LOOP;
END;
但是您的代码有几个错误/缺陷:
EXECUTE IMMEDIATE
要求准确返回一个行。由于UNION
,这不太可能。EXECUTE IMMEDIATE 'SELECT ... FROM ...' INTO NEW_VAR1;
sys.user$
没有任何列defaultpwd
(小写)WHEN others then DBMS_output.put_line('Error!!' || SQLERRM);
来查看实际错误,否则将其隐藏。如果您是SQL的初学者,那就更糟了PASSWORD
进行比较,请简单地使用=
或<>
SELECT ... INTO NEW_VAR1 FROM ...
。不需要EXECUTE IMMEDIATE
。答案 2 :(得分:0)
动态SQL是否有任何特殊原因?您运行的查询中没有 dynamic 。
什么是更糟糕的,是那些选择使用UNION
,这意味着它们可能会将两行或更多行返回到标量变量中,而这行不通。
此外,您滥用了INTO
子句。
这类似于您现在正在执行的操作(示例基于Scott的架构):
SQL> declare
2 l_result varchar2(20);
3 begin
4 execute immediate
5 q'[select deptno into :out1
6 from emp
7 where ename = 'SCOTT'
8 union
9 select deptno into :out2
10 from dept
11 where dname = 'ACCOUNTING']'
12 using out l_result;
13
14 dbms_output.put_line(l_result);
15 end;
16 /
declare
*
ERROR at line 1:
ORA-01744: inappropriate INTO
ORA-06512: at line 4
SQL>
如果您对其进行了修复,则在将2行返回到单个too_many_rows
变量中时,会得到更糟糕的事情:varchar2
:
SQL> declare
2 l_result varchar2(20);
3 begin
4 execute immediate
5 q'[select deptno
6 from emp
7 where ename = 'SCOTT'
8 union
9 select deptno
10 from dept
11 where dname = 'ACCOUNTING']'
12 into l_result;
13
14 dbms_output.put_line(l_result);
15 end;
16 /
declare
*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4
由于其中没有动态变化,请切换为纯select
(当然,将再次返回too_many_rows
):
SQL> declare
2 l_result varchar2(20);
3 begin
4 select deptno
5 into l_result
6 from (select deptno
7 from emp
8 where ename = 'SCOTT'
9 union
10 select deptno
11 from dept
12 where dname = 'ACCOUNTING'
13 );
14
15 dbms_output.put_line(l_result);
16 end;
17 /
declare
*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4
最后,使用适当的变量,即数组:
SQL> declare
2 l_result sys.odcivarchar2list;
3 begin
4 select deptno
5 bulk collect into l_result
6 from (select deptno
7 from emp
8 where ename = 'SCOTT'
9 union
10 select deptno
11 from dept
12 where dname = 'ACCOUNTING'
13 );
14
15 for i in l_result.first .. l_result.last loop
16 dbms_output.put_line(l_result(i));
17 end loop;
18 end;
19 /
10
20
PL/SQL procedure successfully completed.
SQL>
从遇到的错误开始:正如您已经被告知的那样,您需要将每个语句括在其自己的begin-exception-end块中。像这样的简化示例(“简化”意味着您应该正确处理异常。不要仅仅因为它存在而使用WHEN OTHERS;您宁愿让错误发生,识别并正确处理):
declare
l_result sys.odcivarchar2list;
begin
-- start of the first inner begin-exception-end block
begin
select deptno
bulk collect into l_result
from (select deptno
from emp
where ename = 'SCOTT'
union
select deptno
from dept
where dname = 'ACCOUNTING'
);
for i in l_result.first .. l_result.last loop
dbms_output.put_line(l_result(i));
end loop;
exception
when others then
dbms_output.put_Line('handle it');
end;
-- end of the first inner begin-exception-end block
-- start of the second inner begin-exception-end block
begin
null;
exception
when others then null;
end;
-- end of the second inner begin-exception-end block
end;
/