2015-11-12 3 views
2

У меня есть процедура PL/SQL (в базе данных Oracle 12c), которая пытается вставить некоторые данные. Если это не удается, он должен проверить таблицу, чтобы узнать, может ли она найти какую-либо информацию там, чтобы помочь решить проблему. Если он найдет информацию, все будет в порядке, если не регрессирует ошибка.Сохранение исключения PL/SQL и повышение его позже?

Это мой код:

BEGIN 
    -- Try to insert some data. 
    INSERT INTO table VALUES x; 
EXCEPTION 
    WHEN OTHERS THEN 
    BEGIN 
     -- Check a table to fins some info to help solve the problem. 
     -- If we find a row here, we can fix it. 
     -- If not, we should reraise the error. 
     SELECT * INTO y FROM table WHERE a = b; 
     -- Do some more stuff here to fix the problem. 
    EXCEPTION 
     WHEN NO_DATA_FOUND THEN 
     -- We could not find anything in the table, 
     -- so we could not handle the situation. 
     -- Reraise the error. 
     RAISE; 
    END; 
END; 

Проблема здесь состоит в том, что RAISE; оператор поднимает последнее исключение, которое является NO_DATA_FOUND, что SELECT заявления бросило. Исходное исключение из INSERT находится далее в стеке, но не вверху.

Могу ли я как-то «сохранить» ошибку с INSERT и сделать ререйз? Или я могу запустить SELECT INTO, который не выдает ошибку, если ничего не находит? Моя цель здесь - сделать ререйз оригинального исключения INSERT без каких-либо следов исключения NO_DATA_FOUND.

EDIT: Просмотреть комментарии, почему это не дубликат.

+0

Что может пойти не так, во вставке и как вы можете исправить это впоследствии. Не можете ли вы проверить, прежде чем он пойдет не так? – Rene

+0

Я попытался избежать большого контекста в вопросе, чтобы сосредоточиться на проблеме. Я хочу сделать несколько журналов, когда некоторые ограничения внешнего ключа будут нарушены, и создаст пользовательские сообщения об ошибках, если это произойдет. Пользовательские сообщения об ошибках поступают из таблицы, и я выполняю поиск по нарушению внешнего ключа, который был нарушен. – Anders

+0

Возможный дубликат [Как переподнять исключение pl/sql в блоке обработки исключений?] (Http://stackoverflow.com/questions/14978431/how-to-re-raise-pl-sql-exception-in-exception -handling-block) – Stawros

ответ

4

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

Как код:

DECLARE 
    b_reraise BOOLEAN := FALSE; 
BEGIN 
    -- Try to insert some data. 
    INSERT INTO table VALUES x; 
EXCEPTION 
    WHEN OTHERS THEN 
    BEGIN 
     -- Check a table to fins some info to help solve the problem. 
     -- If we find a row here, we can fix it. 
     -- If not, we should reraise the error. 
     SELECT * INTO y FROM table WHERE a = b; 
     -- Do some more stuff here to fix the problem. 
    EXCEPTION 
     WHEN NO_DATA_FOUND THEN 
     -- We could not find anything in the table, 
     -- so we could not handle the situation. 
     -- Reraise the error. 
     b_reraise := TRUE; 
    END; 

    IF b_reraise THEN 
     RAISE; 
    END IF; 
END; 
+0

На стороне примечание, похоже, что это не работает, когда я помещаю часть во внешнем 'EXCEPTION' в хранимую процедуру для повторного использования в других местах. Тогда я не могу вызывать 'RAISE' из процедуры, так как он не является исключением. Но на данный момент он решает мою проблему и вопрос, как я его просил, поэтому принятый ответ. – Anders

+1

Вы всегда можете приложить свой код дополнительным 'BEGIN..EXCEPTION ... END;', поэтому это должно быть возможно. –

1

Может быть что-то вроде этого:

DECLARE 
    l_sqlerrm VARCHAR2(4000); 
    l_sqlerrc NUMBER; 
    l_exc  EXCEPTION; 
BEGIN 
    -- some code with errors 
EXCEPTION 
    WHEN OTHERS THEN 
    l_sqlerrm := SQLERRM; 
    l_sqlerrc := SQLCODE; 
    -- loggin 
    INSERT INTO my_log (code, text) VALUES (l_sqlerrc, l_sqlerrm); 
    COMMIT; 
    -- some your code "Check a table to fins some info to help solve the problem" 
    -- some code to SELECT code INTO l_sqlerrc FROM my_log 
    PRAGMA exception_init(l_exc, l_sqlerrc); 
    RAISE l_exc; 
END; 
+0

Второй аргумент 'PRAGMA exception_init' не может быть переменной, поэтому этот подход не работает, я думаю. Интересная идея. –

+0

@MatthewMcPeak хм ... но почему это сработало?CREATE TABLE t1 (первичный ключ идентификатора номера); Вставить в значения t1 (1); совершить; DECLARE l_sqlerrm VARCHAR2 (4000); l_sqlerrc НОМЕР; l_tmp НОМЕР; l_exc ИСКЛЮЧЕНИЕ; НАЧАЛО ВСТАВИТЬ В Т1 ЗНАЧЕНИЯ (1); COMMIT; ИСКЛЮЧЕНИЕ КОГДА ДРУГИЕ ТОГДА l_sqlerrm: = SQLERRM; l_sqlerrc: = SQLCODE; PRAGMA exception_init (l_exc, l_sqlerrc); BEGIN SELECT id INTO l_tmp ОТ t1 ГДЕ 1 = 2; ИСКЛЮЧЕНИЕ КОГДА NO_DATA_FOUND THEN RAISE l_exc; END; END; – hinotf

+0

Попытки использовать переменную во втором аргументе могут вызвать ошибку PLS-00702. Прочитайте документацию Oracle по этой ошибке - ясно (из этого источника), что они не ожидают или не поддерживают переменную в этой позиции, даже если она работает в вашем примере. Я бы не использовал это для производственного кода без предварительной регистрации SR с Oracle, чтобы убедиться, что он поддерживается. Потому что вещи, которые работают, но не поддерживаются, могут не работать в более поздних версиях. –

Смежные вопросы