0

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

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 语句总是执行,因此总是引发异常,即使返回一行也是如此。我不确定为什么。如果有更好的方法来处理这种逻辑,我也愿意;)

4

2 回答 2

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;

如果选择返回超过 1 行,这将引发 TOO_MANY_ROWS。如果您不希望这种情况发生,即超过 1 行是可以的,您可以在查询中添加“AND ROWNUM = 1”。

于 2009-11-10T16:18:34.757 回答
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;

我不太喜欢显式游标,所以我也会推荐这个合成器:

BEGIN
   SELECT ... 
     INTO r_prmRecord 
     FROM ... 
    WHERE ... AND rownum = 1; -- your cursor query
EXCEPTION
   WHEN no_data_found THEN
      RAISE X_INVALID_PNUM;
END;
于 2009-11-10T16:16:03.420 回答