我有一个pl sql代码,它按顺序执行三个查询以确定匹配级别并执行一些逻辑
问题是 - 当第一个查询没有结果(完全有效的场景)时,我得到ORA-01403没有找到数据。
我明白我需要在NO_DATA_FOUND中加入[Exception子句] - 但是如何添加它并继续下一个查询?
PL/SQL Code
SELECT A into PARAM A FROM SAMPLE WHERE SOME CONDITION;
-- GOT ORA-01403 No data found HERE
MATCH_LEVEL =1;
if A is null then
do some logic;
end if
SELECT A INTO PARAM_B FROM SAMPLE WHERE SOME OTHER CONDITION
MATCH_LEVEL =2
if A is null then
do some logic 2;
end if
SELECT A INTO PARAM_B FROM SAMPLE WHERE SOME OTHER CONDITION
MATCH_LEVEL =3
if A is null then
do some logic 3;
end if
END PL/SQL Code
答案 0 :(得分:3)
用SELECT INTO
begin-end;
begin
-- your faulty statement here
Exception
When NO_DATA_FOUND Then
-- Do what you want or nothing
WHEN TOO_MANY_ROWS THEN
-- what if you get more then one row? and need specific handler for this
When OTHERS Then
-- do something here or nothing (optional - may happen if you have more than your SELECT INTO between 'begin' and 'Exception')
end;
这就像try
PL/Sql
块一样
使用此技术,您可以记录语句失败的原因。
答案 1 :(得分:3)
Declare
--your declarations
begin
SELECT A into PARAM A FROM SAMPLE WHERE SOME CONDITION;
-- GOT ORA-01403 No data found HERE
Begin
MATCH_LEVEL =1;
if A is null then
do some logic;
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line ('Error...');
END;
--- and son on for other blocks
end;
答案 2 :(得分:2)
对于SELECT ... INTO ...
语句,PL / SQL引擎假定查询返回一行,且只返回一行。如果没有行或多个行,则会引发异常。
FWIW,您可以通过使用聚合函数来处理此类情况,而无需使用异常处理。这样,总是只是结果集中的一行。
假设您的行中A
不能为NULL
:
SELECT MAX(A) into PARAM A FROM SAMPLE WHERE SOME CONDITION;
-- A would be NULL if there was *no* row. Otherwise, it is *the* value for *the* row
MATCH_LEVEL =1;
if A is null then
do some logic;
end if
如果NULL
值是可能的情况,只需添加额外的COUNT(*)
列:
SELECT MAX(A), COUNT(*) into A, HAS_FOUND_ROW FROM SAMPLE WHERE SOME CONDITION;
if HAS_FOUND_ROW > 0 then
...
end if;
答案 3 :(得分:1)
Oracle不允许您在不返回任何行的情况下打开隐式游标(即代码块正文中的select
语句)。你有两个选择(3个真正的,计算@ Sylvain的答案,但这是一种不寻常的方法):使用显式游标或处理错误。
显式光标
显式游标是DECLARE
部分中的游标,必须手动打开并提取(或在FOR
循环中)。这有一个额外的好处,如果您正确地参数化查询,您可以编写一次并多次使用它。
DECLARE
a sample.a%type;
MATCH_LEVEL number;
cursor cur_params (some_column_value number) is
SELECT A FROM SAMPLE WHERE some_column = some_column_value;
BEGIN
MATCH_LEVEL := 1;
open cur_params (match_level);
fetch cur_params into a;
close cur_params;
if A is null then
null; --some logic goes here
end if;
MATCH_LEVEL := 2;
open cur_params (match_level);
fetch cur_params into a;
close cur_params;
if A is null then
null; --some logic goes here
end if;
end;
处理错误
如果您选择处理错误,则需要围绕将引发错误的代码创建BEGIN...END
块。当忽略错误时,确保您只是忽略您希望避免的特定错误,从您期望的特定语句生成时,这一点至关重要。例如,如果您只是将EXCEPTION
部分添加到现有的BEGIN...END
块中,您就无法知道哪个语句生成了它,或者即使它确实是您预期的错误。
DECLARE
a sample.a%type;
MATCH_LEVEL number;
BEGIN
MATCH_LEVEL := 1;
BEGIN
SELECT A into A FROM SAMPLE WHERE some_column = MATCH_LEVEL;
EXCEPTION
WHEN NO_DATA_FOUND THEN
null; --Do nothing
END;
if A is null then
null; --some logic goes here
end if;
MATCH_LEVEL := 2;
BEGIN
SELECT A into A FROM SAMPLE WHERE some_column = MATCH_LEVEL;
EXCEPTION
WHEN NO_DATA_FOUND THEN
null; --Do nothing
END;
if A is null then
null; --some logic goes here
end if;
end;
虽然我不鼓励它,但您可以在同一个异常块中捕获任何其他错误。但是,根据定义,这些错误是出乎意料的,所以放弃它们是不好的做法(你永远不会知道它们甚至发生了!)。一般来说,如果在异常处理中使用WHEN OTHERS
子句,则该子句应始终以RAISE;
结束,以便将错误传递到下一级并且不会丢失。