ORA-04091 при создании или замене триггера xxx перед вставкой обновления в xxx - PullRequest
0 голосов
/ 23 октября 2009

Может кто-нибудь помочь мне исправить триггер ниже? Мне задают эту проблему, но мои технические навыки ограничены.

Мой скрипт обнаружил ошибку ниже (ORA 4091):

ОБРАБОТКА СТАНДАРТНОГО ПО, Номер заказа: 27179

......................................

Обновление статуса заказа на поставку ..

Выполнено утверждение.

dist id 611294gl сумма 10000.88 bill_del_amount 0 l_amount 10000.88

произошло исключение ** ORA-04091: таблица PO.PO_DISTRIBUTIONS_ALL мутирует,

триггер / функция может его не видеть **

ORA-06512: в "APPS.XXAET_PO_DELIVER_TO_TRG",

строка 22 * ​​1023 *

ORA-01403: данные не найдены

ORA-04088: ошибка при выполнении триггера

APPS.XXAET_PO_DELIVER

Процедура PL / SQL успешно завершена.

SQL>

Мне удается найти настроенный триггер на клиентском компьютере, но после исследования я не могу точно определить, что не так с SQL. ПОМОГИТЕ!

CREATE OR REPLACE TRIGGER apps.xxaet_po_deliver_to_trg
BEFORE INSERT OR UPDATE ON po_distributions_all
   FOR EACH ROW
DECLARE
   l_emp_name   VARCHAR2 (300);
   l_sqlcode    VARCHAR (30)   := SQLCODE;
   l_sqlerrm    VARCHAR (400)  := SUBSTR (SQLERRM, 1, 399);
   x_profile_value  VARCHAR (10) ;
BEGIN

x_profile_value := fnd_profile.value('ORG_ID');
  Select Ship_To_Location_ID
  INTO :NEW.Deliver_To_Location_Id
  from PO_LINE_LOCATIONS_ALL
  WHERE line_location_id = :NEW.line_location_id
  AND ORG_ID = x_profile_value
  ;

EXCEPTION
   WHEN OTHERS
   THEN
      NULL;

   UPDATE PO_DISTRIBUTIONS_ALL SET Deliver_To_Location_Id = :NEW.Deliver_To_Location_Id
   WHERE line_location_id = :NEW.line_location_id;

END;

/

Спасибо большое! Кеннет.

Ответы [ 4 ]

5 голосов
/ 23 октября 2009

Ошибка таблицы мутаций означает, что код триггера не может выдавать операторы DML в своей таблице-владельце. Это чтобы избежать рекурсивного поведения. Решение довольно простое. Удалить оператор UPDATE.

Цель этого заявления не совсем ясна. Это довольно часто, так как ошибка ORA-4091 обычно указывает на плохой дизайн, такой как недостаточно нормализованная модель данных. Я думаю, что это ваша ситуация. Следовательно, для решения проблемы требуется гораздо больше знаний о бизнесе, чем у нас.

Также кажется, что ваш оператор SELECT не выполняется (стек ошибок при публикации немного запутан). Вы пытаетесь подавить сбой этого оператора с помощью пресловутой конструкции WHEN OTHERS THEN NULL;. Это сосать! Удалите это немедленно. Вам нужно , чтобы знать, что ваш код не работает, и почему. Если заполнение: NEW.Deliver_To_Location_Id не является обязательным, поэтому вы не возражаете, если поиск "не удается" заменить OTHERS на NO_DATA_FOUND.

3 голосов
/ 23 октября 2009

Основной причиной этой проблемы является использование триггеров для выполнения чего-либо, кроме ведения журнала или других задач, не связанных с приложением. Довольно широко считается очень плохой практикой использовать их для манипулирования данными таким образом.

В дополнение к этому используется условие EXCEPTIONS для автоматического перехвата ошибок и запуска этого обновления. И использование WHEN OTHERS THEN NULL - трагедия, которая должна произойти.

Все ужасные практики программирования на PL / SQL, которые никогда не должны были проходить проверку кода.

Время рефакторинга.

2 голосов
/ 23 октября 2009

Основной причиной ORA-04091 является обработка ИСКЛЮЧЕНИЯ - вы ничего не можете сделать с таблицей, к которой прикреплен триггер. В этом случае - PO_DISTRIBUTIONS_ALL

Ссылка: ORA-04091 Ошибка

Я предлагаю вам инкапсулировать логику в хранимую процедуру и вызывать ее в хранимых процедурах INSERT / UPDATE до операторов INSERT / UPDATE.

1 голос
/ 28 октября 2009

Как упоминалось в предыдущих ответах, вы получаете ошибку мутации, потому что вы обновляете ту же таблицу в триггере, что недопустимо.

Поскольку вы используете триггер «перед обновлением и вставкой», все, что вам нужно сделать, это установить: new.deliver_to_location_id с правильным значением. Поскольку вы уже делаете это в операторе select, чтобы исправить свой триггер, просто удалите оператор update, поскольку ваш оператор select уже обновляет поле записи.

В качестве усовершенствования вы можете заменить исключение "когда другие" на "когда нет_данных", это поможет вам выбросить все другие непредвиденные ошибки.

...