(чайник) Ошибка ORA-01403 при select ... into... для НЕсуществующей строки. Как побороть ?

GrayCity
Дата: 09.06.2006 16:22:41
hi all.

Есть PL/SQL-функция, к-рой передаётся наименование контрагента (параметр clientName) и она должна проверить его наличие в справочнике (table clients, поля: ID number, name varchar2) и:
1) если его там еще нет, то добавить новую строку с определением нового ID
2) а если есть - взять ID этой строки вместо добавления.

Вот фрагмент этой PL/SQL функции:
FUNCTION newClient(clientName IN VARCHAR2) RETURN NUMBER
IS
  xClientId CLIENTS.ID%TYPE;
BEGIN
  SELECT Id INTO xClientId FROM CLIENTS WHERE NAME = clientName;
  IF SQL%NOTFOUND THEN
    INSERT INTO Clients (Name) VALUES (clientName) RETURNING Id INTO xClientId;
  END IF; 
  -- ... МНОГО ЕЩЕ ЧЕГО
  RETURN xClientId;
END newClient; 

При попытке запуска этого кода для значения clientName = <НЕ_существующее_еще_название> вылезает ora-0403 (no data found).
В отладчике эта ошибка происходит в момент выполнения команды
SELECT Id INTO xClientId FROM CLIENTS WHERE NAME = clientName;
Где я ошибся и как это побороть ?
iV@n
Дата: 09.06.2006 16:26:13
смотреть в сторогу exception
как вариант заменить
  SELECT Id INTO xClientId FROM CLIENTS WHERE NAME = clientName;
  IF SQL%NOTFOUND THEN
    INSERT INTO Clients (Name) VALUES (clientName) RETURNING Id INTO xClientId;
  END IF;
на
 begin
  SELECT Id INTO xClientId FROM CLIENTS WHERE NAME = clientName;
 exception
  when no_data_found then
    INSERT INTO Clients (Name) VALUES (clientName) RETURNING Id INTO xClientId;
 end;
GrayCity
Дата: 09.06.2006 16:29:12
Не могу я смотреть в сторону exception'a!! Потому что тогда он сразу зайдёт в секцию exception и после отработки исключения немедленно вылетит из функции, а у меня в ней еще ОЧ-ЧЕНЬ много чего надо делать!
dmidek
Дата: 09.06.2006 16:32:49
GrayCity
Не могу я смотреть в сторону exception'a!! Потому что тогда он сразу зайдёт в секцию exception и после отработки исключения немедленно вылетит из функции, а у меня в ней еще ОЧ-ЧЕНЬ много чего надо делать!

Не вылетит.
Читайте про блоки и exceptions.
waspwort
Дата: 09.06.2006 16:35:47
не вылетит, если ты проблемный код возьмешь в скобки begin..end
tru55
Дата: 09.06.2006 16:36:51
Существуют вложенные блоки. Типа
BEGIN
  ...
   BEGIN
     SELECT ... INTO

   EXCEPTION

   END;

   < здесь много чего делаем >
END;
iV@n
Дата: 09.06.2006 16:45:04
GrayCity
Не могу я смотреть в сторону exception'a!! Потому что тогда он сразу зайдёт в секцию exception и после отработки исключения немедленно вылетит из функции, а у меня в ней еще ОЧ-ЧЕНЬ много чего надо делать!

ты б сначала заменил, посмотрел, потом прочитал об эксепшинах, а потом уже делал такие утверждения
andrey_anonymous
Дата: 09.06.2006 16:49:41
GrayCity

1) если его там еще нет, то добавить новую строку с определением нового ID
2) а если есть - взять ID этой строки вместо добавления.

Рабочих решений на самом деле много. Но не Ваше :)
1) про exception уже говорили
2) MERGE
3) SELECT MAX(ID) INTO..
4) UPDATE... SET ID=ID WHERE... ; IF SQL%ROWCOUNT=0 THEN INSERT...
ну и т.д.
GrayCity
Дата: 09.06.2006 17:09:02
2 iV@n: да, ты оказался прав. Это я что-то в книге не так понял (к тому же на знал, что exception можно вместе с "пробным" оператором заключать в begin...end посередине кода - спасибо tru55).

Всё заработало, всем спасибо!
GrayCity
Дата: 09.06.2006 20:33:54
автор топика
Это я что-то в книге не так понял
- нашел, где читал:
Урман Скот, "Oracle 9i. Программирование на языке PL/SQL" (изд-во Лори, 2006, ISBN 0-07-219147-3; переводчик О.Труфанов).
На странице 249 (глава 7) приведено два примера в виде рисунков, и в примере 1 изображено возникновение исключения во вложенном блоке, его обработка и передача управления во внешний ("охватывающий" блок). Всё бы хорошо, да только стрелочка от фразы "Сюда передаётся управление программой" нарисована НЕ на операторы этого внешнего блока, а прямо на его END.
Вот что там нарисовано:
DECLARE
   A EXCEPTION;
BEGIN

  BEGIN
     RAISE A;               <-------- искл. ситуация порождается во внутр блоке
  EXCEPTION
     WHEN A THEN            <-------- а обрабатывается также в этом блоке
     ....
  END;

END;                       <-------- сюда передается управление программой

Ну, и как это можно было понять, не имея опыта работы с PL/SQL ?

У кого есть эта книжка - проверьте, если хотите.