ORACLE перед триггером обновления не срабатывает, когда столбец изменяется в другом триггере

Я использую ORACLE 12c.

На столе у ​​меня 2 триггера, оба "до обновления". Один из триггеров срабатывает при обновлении столбца, и внутри этого триггера другой столбец получает новое значение. Второй триггер должен срабатывать при обновлении этого второго столбца. Но он этого не сделал.

create table TRIGGER_TEST
(
    col1 varchar2(64),
    col2 varchar2(64),
    col3 varchar2(64)
);

create or replace trigger TR_TRIGGER_TEST_1 
before update of COL1 on TRIGGER_TEST
for each row
begin
    dbms_output.put_line('here we are in TR_TRIGGER_TEST_1');
    :new.col2 := 'only testing';
end;
/

create or replace trigger TR_TRIGGER_TEST_2
before update of COL2 on TRIGGER_TEST
for each row
begin
    dbms_output.put_line('here we are in TR_TRIGGER_TEST_2');
    :new.col3 := 'trigger_test_2 has fired';
end;
/


insert into TRIGGER_TEST values ('1_col1','1_col2','1_col3');
select * from TRIGGER_TEST;

COL1                 COL2              COL3                                                    
----------------------------------------------------------------
1_col1               1_col2            1_col3                                                          

После того, как я вставил строку, я выполняю ОБНОВЛЕНИЕ. И я ожидаю, что COL1 = «теперь посмотрим», COL2 = «только тестирование» и COL3 = «триггер_тест_2 сработал».

update TRIGGER_TEST set COL1 = 'now we will see';

Но я получаю следующее:

select * from TRIGGER_TEST;


COL1                 COL2              COL3                                                    
----------------------------------------------------------------
now we will see      only testing      1_col3                                                          

Кто-нибудь может мне это объяснить? Я действительно уверен, что с предыдущими версиями ORACLE этот сценарий сработал. Но теперь это не так.


person virtualbee    schedule 07.06.2017    source источник
comment
Добро пожаловать в СО! Это ваш первый вопрос, и он хорошо написан, со значимым заголовком, правильными тегами, хорошим форматированием; он даже показывает, что вы сделали, и позволяет людям воспроизвести тест. +1 !   -  person Aleksej    schedule 07.06.2017
comment
.. и если вы хотите продолжать использовать SO правильно, здесь вы найдете что-то о том, что делать, когда кто-то вам отвечает .   -  person Aleksej    schedule 07.06.2017


Ответы (2)


Я действительно уверен, что с предыдущими версиями ORACLE этот сценарий сработал.

Это не так. Я запустил ваш код в 11gR2 и получил тот же результат:

set serveroutput on

update TRIGGER_TEST set COL1 = 'now we will see';

here we are in TR_TRIGGER_TEST_1


1 row updated.

select * from TRIGGER_TEST;

COL1                           COL2                           COL3                          
------------------------------ ------------------------------ ------------------------------
now we will see                only testing                   1_col3                        

before update of COL2 on TRIGGER_TEST – это событие DML. а>. Вы создаете простые триггеры DML:

Триггер DML создается либо для таблицы, либо для представления, и его инициирующее событие состоит из операторов DML DELETE, INSERT и UPDATE. ...

Когда вы выпускаете свое обновление, DML вызывает срабатывание первого триггера. Но когда вы назначаете новое значение внутри этого триггера:

    :new.col2 := 'only testing';

.. это не оператор DML — это не отдельное обновление.

Если присвоение значения таким образом вызвало срабатывание триггера, то если вы вместо этого сделали:

    :new.col1 := 'something';

... затем этот первый триггер будет срабатывать снова, рекурсивно, пока вы не столкнетесь с ошибкой ORA-00036: maximum number of recursive SQL levels (50) exceeded. Это явно было бы плохо.

Вам придется повторить назначение col3 в первом триггере, если это то, что вам нужно. Для более сложных побочных эффектов, которые вы хотите получить при нажатии любого триггера, у вас может быть процедура, которая выполняет любые необходимые действия (которые не влияют на эту таблицу), а затем вызываете ее из обоих триггеров. Хотя тогда вам понадобится механизм, чтобы убедиться, что процедура не вызывается дважды, если обновление DML затрагивает оба столбца, что вызывает срабатывание обоих триггеров.

person Alex Poole    schedule 07.06.2017
comment
Большое спасибо за ваше объяснение! Теперь понятно почему не работает..... - person virtualbee; 07.06.2017

«обновление COL2» в триггере будет означать обновление с использованием инструкции SQL, такой как UPDATE или MERGE, и никак иначе. Почему вы не кодируете второй триггер в первом?

person Allen    schedule 07.06.2017