我有一个光标,用于获取其他一些处理的初步信息。支持游标的查询可能不会返回任何行,在这些极少数情况下,我们希望引发一个特殊的异常(在其他地方处理和记录,因此处理不会被强制停止),以便用户知道什么是最有可能的输入不好。这是它的样子:
open c_getPrs(in_pnum);
loop
fetch c_getPrs
into r_rpmRecord;
if c_getPrs%NOTFOUND then
raise X_INVALID_PNUM;
end if;
exit when c_getPrs%rowcount > 1 /*or c_getPrs%NOTFOUND*/;
end loop;
close c_getPrs;
问题是if语句始终执行,因此即使返回行,也始终引发异常。我不知道为什么。如果有更好的方法来处理这种逻辑,我也会对此持开放态度;)
答案 0 :(得分:7)
您的代码总是围绕循环两次,因此如果光标返回的行少于2行,则会失败。你可能根本不需要循环:
open c_getPrms(in_pnum);
fetch c_getPrms
into r_prmRecord;
if c_getPrms%NOTFOUND then
raise X_INVALID_PNUM;
end if;
close c_getPrms;
我宁愿完全避开光标,而是使用“select into”:
begin
select ...
into r_prmRecord
from ...
where ...
exception
when no_data_found then
raise X_INVALID_PNUM;
end;
如果select返回多于1行,这将引发TOO_MANY_ROWS。如果您不希望这种情况发生,即多于1行就可以了,您可以在查询中添加“AND ROWNUM = 1”。
答案 1 :(得分:5)
你的问题在于退出条件:在第一次传递时c_getPrms%rowcount是1,所以你得到另一个引发异常的传递。
由于您只需要一次抓取,我建议使用以下构造:
OPEN c_getPrms(l_input);
FETCH c_getPrms
INTO r_prmRecord;
IF c_getPrms%NOTFOUND THEN
RAISE X_INVALID_PNUM;
END IF;
CLOSE c_getPrms;
我不太喜欢显式光标,所以我也建议使用这个synthax:
BEGIN
SELECT ...
INTO r_prmRecord
FROM ...
WHERE ... AND rownum = 1; -- your cursor query
EXCEPTION
WHEN no_data_found THEN
RAISE X_INVALID_PNUM;
END;