游标 - 即使返回行,%notfound也为true

时间:2009-11-10 16:09:47

标签: oracle plsql cursors

我有一个光标,用于获取其他一些处理的初步信息。支持游标的查询可能不会返回任何行,在这些极少数情况下,我们希望引发一个特殊的异常(在其他地方处理和记录,因此处理不会被强制停止),以便用户知道什么是最有可能的输入不好。这是它的样子:

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语句始终执行,因此即使返回行,也始终引发异常。我不知道为什么。如果有更好的方法来处理这种逻辑,我也会对此持开放态度;)

2 个答案:

答案 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;