java.sql.BatchUpdateException: ORA-04091 перед вставкой триггера - PullRequest
0 голосов
/ 16 сентября 2011

Я получаю любопытную ошибку ПЕРЕД ВСТАВИТЬ ТРИГГЕР, которую я не могу понять. Даже после прочтения нескольких вопросов, размещенных здесь с похожими проблемами

не удалось обработать "метод": category_id = 'foo' и request_id = '99' ошибка: java.sql.BatchUpdateException: ORA-04091: таблица SCHEMA.ANIMAL_TABLE мутирует, триггер / функция может его не видеть ORA-06512: at «SCHEMA.TRIGGER_NAME», строка 7 ORA-04088: ошибка во время выполнения триггер 'SCHEMA.TRIGGER_NAME'

Вот триггер:

CREATE OR REPLACE TRIGGER TRIGGER_NAME 
BEFORE INSERT ON animal_table FOR EACH ROW WHEN (NEW.animal_type = 'cats')

DECLARE    base_animal_id NUMBER(19,0);   base_amount NUMBER(19,0);

BEGIN

SELECT animal_nbr INTO base_animal_id 
FROM animal_table 
WHERE category_id = :NEW.category_id AND summary_id = :NEW.summary_id 
AND animal_type = 'special'; 

SELECT animal_amount INTO base_amount 
FROM animal_table 
WHERE category_id = :NEW.category_id AND summary_id = :NEW.summary_id 
AND animal_type = 'special';


IF :NEW.category_id = 'foo' THEN

  :NEW.animal_info1 := base_animal_id;   
  :NEW.animal_info2 := base_amount;   
  :NEW.animal_info3 := '00';

END IF;

END;

Я знаю правила, касающиеся изменений в той же таблице, в которой удерживается триггер, но я также выделил кое-что, что должно работать при изменении новых столбцов и только для полей: NEW. Я также думал, что это может пропустить ОБНОВЛЕНИЕ как событие триггера, но это не так. Кто-нибудь может мне помочь? Как я новичок в триггерах и PL / SQL.

1 Ответ

0 голосов
/ 16 сентября 2011

Сообщение об ошибке не имеет ничего общего с обновлением таблицы.Вы не можете SELECT из таблицы, которая в настоящее время изменяется в триггере ROW level .

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

Вы можете обойтись без триггера уровня строки и промежуточной таблицы, если сможете определить строки, подлежащие последующей обработке внутри триггера уровня оператора, например, путем проверки animal_type = 'cats' и category_id = 'foo'.

Если это так, следующий триггер (непроверенный !!!) может делать то, что вы хотите (вместо того, который у вас есть)

CREATE OR REPLACE TRIGGER TRIGGER_NAME 
AFTER INSERT ON animal_table 
BEGIN

  UPDATE animal_table
     SET (animal_info1, 
          animal_info2, 
          animal_info3) = (SELECT animal_nbr, animal_amount, '00'
                           FROM animal_table t2
                           WHERE t2.category_id = animal_table.category_id
                             AND t2.sumary_id = animal_table.summary_id
                             AND t2.animal_type = 'special'
                          )
  WHERE animal_type = 'cats'
    AND category_id = 'foo'

END;

Еще одна более общая вещь PL / SQL: Вам не нужно запускать один SELECT для каждого столбца, который вы хотите извлечь, вы можете сделать это в одном операторе select, если условия одинаковы:

SELECT animal_nbr, animal_amount
    INTO base_animal_id, base_amount 
FROM animal_table 
WHERE category_id = :NEW.category_id 
  AND summary_id = :NEW.summary_id 
  AND animal_type = 'special';

(Обратите внимание на два столбца ввыбрать и в список)

...