курсоры -% notfound имеет значение true, даже когда строка возвращается - PullRequest
0 голосов
/ 10 ноября 2009

У меня есть курсор, который используется для получения некоторой предварительной информации для некоторой другой обработки. Возможно, что запрос, поддерживающий курсор, может не вернуть никаких строк, и в этих редких случаях мы хотим вызвать специальное исключение (обработанное и зарегистрированное в другом месте, чтобы обработка не была полностью остановлена), чтобы пользователь знал, что наиболее вероятно плохой ввод. Вот как это выглядит:

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 ]

7 голосов
/ 10 ноября 2009

Ваш код всегда обходит цикл дважды, и поэтому не выполняется, если курсор возвращает менее 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;

Я бы предпочел вообще избегать курсора и использовать вместо этого «выбрать в»:

begin
   select ...
   into   r_prmRecord
   from   ...
   where  ...
exception
   when no_data_found then
      raise X_INVALID_PNUM;
end;

Это повысит TOO_MANY_ROWS, если выборка возвращает более 1 строки. Если вы не хотите, чтобы это происходило, то есть более 1 строки в порядке, вы можете просто добавить «И ROWNUM = 1» к запросу.

5 голосов
/ 10 ноября 2009

ваша проблема связана с вашим условием выхода: при первом проходе 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;
...