#oracle #error-handling #plsql #oracle10g #oracle11g
#Oracle #обработка ошибок #plsql #oracle10g #oracle11g
Вопрос:
У меня есть следующее…
IF CONDITION1 THEN
-- SELECT STATEMENT MIGHT RETURN DATA
IF CONDITION2 THEN
-- SELECT COUNT
IF CONDITION3 THEN
INSERT INTO TABLE
(
---
)
VALUES (
---
);
End IF;
END IF;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN;
END of Trigger
Это правильный способ обработки исключения для оператора select внутри CONDITION1?
Ответ №1:
В PL / SQL нет способа вернуться на место ошибки, поэтому вам нужно создать блок вокруг части, которую вы хотите игнорировать конкретные ошибки:
IF CONDITION1 THEN
BEGIN
-- SELECT STATEMENT MIGHT RETURN DATA
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
IF CONDITION2 THEN
-- SELECT COUNT
IF CONDITION3 THEN
INSERT INTO TABLE
(
---
)
VALUES (
---
);
End IF;
END IF;
END IF;
END TRIGGER_NAME;
Альтернативой является использование явного курсора, который не возвращает ошибку, когда он пуст:
DECLARE
CURSOR cur_sample is select dummy from dual where 1=0;
v_dummy dual.dummy%type;
BEGIN
IF CONDITION1 THEN
open cur_sample;
fetch cur_sample into v_dummy;
close cur_sample;
IF CONDITION2 THEN
-- SELECT COUNT
IF CONDITION3 THEN
INSERT INTO TABLE
(
---
)
VALUES (
---
);
End IF;
END IF;
END IF;
END;
Комментарии:
1. плюс 1 за то, как создать пустой обработчик ошибок в pl.sql — null;
Ответ №2:
Зависит от того, что вы подразумеваете под «правильным». То, что вы представили, синтаксически допустимо, да. Но вы не сказали нам, что вы на самом деле хотите, чтобы произошло, поэтому мы не можем сказать вам, действительно ли опубликованный вами код будет делать то, что вы хотите.
С точки зрения бизнес-логики, вы уверены, что это действительно не ошибка, если ваш SELECT INTO возвращает 0 строк? Если вы перехватываете и проглатываете исключение, это означает, что вы знаете, что на самом деле это не ошибка. Однако, если вы кодируете SELECT В, это подразумевает, что вы ожидаете ровно одну строку. Конечно, возможно, что оба эти утверждения верны, но было бы более распространенным, что это действительно исключение и что его не следует просто проглатывать и игнорировать.
В общем, я бы предпочел поместить обработчик исключений как можно ближе к запросу, который может вызвать исключение, насколько это возможно. Я бы счел более чистым иметь что-то вроде
IF condition1
THEN
BEGIN
<<select statement>>
EXCEPTION
WHEN no_data_found
THEN
<<do something>>
END;
IF condition2
THEN
...
END IF;
END IF;
Таким образом, если вы в конечном итоге получите несколько мест в вашей процедуре, где может быть сгенерировано исключение NO_DATA_FOUND, будет ясно, какие исключения ожидаемы, а какие неожиданны.
Когда вы доходите до того, что у вас есть три уровня вложенных операторов IF, я склонен подозревать, что вы хотите преобразовать код в несколько процедур, чтобы сделать код более понятным. Например, вместо того, чтобы иметь вложенный блок PL / SQL, который выполняет инструкцию SELECT, перехватывает исключение и обрабатывает исключение, вероятно, было бы понятнее иметь отдельную функцию, которая все это делала, а затем вызывать эту функцию из вашего триггера.
Комментарии:
1. @Allan — Почему нет? Синтаксически допустимо возвращать данные из блока PL / SQL в обработчике исключений. Возможно, это неправильное поведение, но это допустимый синтаксис SQL> создать таблицу t (номер col1 ); Таблица создана. SQL> создайте триггер trg_t 2 перед вставкой в t3 для каждой строки 4 объявите 5 l_emp_rec emp%rowtype; 6 начните 7 выберите * 8 в l_emp_rec 9 из emp 10, где empno = :new.col1; 11 исключение 12, когда no_data_found 13, затем 14 возвращает; 15 завершает; 16 / Триггер создан. SQL> вставить в t значений (1); создана 1 строка.
2. Вы правы (конечно). Я был совершенно не осведомлен об этой команде (за пределами функций). Я все еще думаю, что поведение будет не таким, какое ожидал OP, что, как я полагаю, было возобновлением выполнения с места ошибки.
3. @Allan — Я согласен, что вполне возможно, что поведение — это не то, чего на самом деле хочет Каллс. Трудно понять, не имея лучшего объяснения того, что Каллс хочет, чтобы произошло.
4. Все, что я хочу, это если у меня есть условие 1, у меня есть оператор SELECT, и он может выйти без данных. В этом случае я хочу, чтобы оно перешло в Exception и вернулось обратно вызывающей стороне.
5. @kalls — Это то, что делает ваш код. Существуют лучшие способы ее кодирования (которые я обсуждаю выше), но опубликованный вами код, похоже, соответствует этому требованию.