курсоры -% notfound истинно, даже если строка возвращается

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

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 выполняется ВСЕГДА, поэтому исключение всегда возникает, даже когда возвращается строка. Не знаю почему. Если есть лучший способ справиться с такой логикой, я тоже открыт для этого;)


person FrustratedWithFormsDesigner    schedule 10.11.2009    source источник
comment
Зачем вы создаете цикл, если вы будете получать только один раз? Может быть, ваш %rowcount ведет себя не так, как вы думаете, и цикл выполняется более одного раза?   -  person Adam Hawkes    schedule 10.11.2009
comment
Раньше мы извлекали и использовали более одной записи, но похоже, что так и останется (только 1 запись). Как оказалось, это было условием выхода. Изменение его на = 1 вместо ›1 устранило проблему, но затем Тони также указал, что цикл на самом деле больше не нужен.   -  person FrustratedWithFormsDesigner    schedule 10.11.2009


Ответы (2)


Ваш код всегда обходит цикл дважды и поэтому терпит неудачу, если курсор возвращает менее 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 строки. Если вы не хотите, чтобы это происходило, т.е. допускается наличие более одной строки, вы можете просто добавить в запрос «AND ROWNUM = 1».

person Tony Andrews    schedule 10.11.2009
comment
Хех, это даже лучше. Когда-то цикл был действительно необходим (мы проверили больше, чем первую запись), поэтому, думаю, я не заметил, что он больше не нужен. - person FrustratedWithFormsDesigner; 10.11.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;
person Vincent Malgrat    schedule 10.11.2009
comment
Интересно. По какой причине вы оба предпочитаете неявный курсор явному? Меня заставили понять, что явные курсоры, как правило, выполняются быстрее, но я изучал PL / SQL всего месяц или около того, так что я все еще учусь. - person FrustratedWithFormsDesigner; 10.11.2009
comment
@ Разочарованный: они идентичны по производительности. Я считаю, что неявные курсоры легче читать и, следовательно, их легче поддерживать. См. Этот SO, например: stackoverflow.com / questions / 1577734 / - person Vincent Malgrat; 10.11.2009
comment
Хорошо, это хороший момент. В этом случае запрос довольно длинный и неприятный, поэтому я думаю, что мою процедуру будет легче читать, если оператор select не загромождает ее. Моя IDE позволяет мне щелкнуть имя курсора, удерживая клавишу Ctrl, и сразу перейти к определению курсора. У меня также есть сильное чувство, что этот курсор, возможно, потребуется использовать еще в нескольких местах (в одном из них БУДЕТ настоящий цикл;)), поэтому я думаю, что пока оставлю это явным. - person FrustratedWithFormsDesigner; 10.11.2009