当在另一个触发器中更改列时,ORACLE "before update" 触发器不会触发

ORACLE "before update" trigger does not fire when column is changed within another trigger

我正在使用 ORACLE 12c。

在 table 上,我有 2 个触发器,都是 "before update"。 其中一个触发器在更新列时触发,并且在该触发器中,另一列获得新值。第二个触发器应该在更新第二列时触发。但是他没有。

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= "now we will see"、COL2="only testing" 和 COL3 = "trigger_test_2 has fired".

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 版本,这个 szenario 已经奏效了。但是现在没有了。

触发器中的

"update of COL2" 意味着使用 SQL 语句(例如 UPDATE 或 MERGE)进行更新,而不是其他方式。为什么不在第一个中编写第二个触发器?

I am really sure, that with former ORACLE versions this szenario has worked.

还没有。我 运行 你在 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 event clause. You are creating simple DML triggers:

A DML trigger is created on either a table or view, and its triggering event is composed of the DML statements DELETE, INSERT, and UPDATE. ...

当您发布更新时,DML 会触发第一个触发器。但是当您在该触发器中分配一个新值时:

    :new.col2 := 'only testing';

.. 那是 不是 DML 语句 - 它不是单独的更新。

如果以这种方式赋值确实会触发触发器,那么如果您这样做:

    :new.col1 := 'something';

... 然后第一个触发器将递归地再次触发,直到您遇到错误 ORA-00036: maximum number of recursive SQL levels (50) exceeded。那显然是不好的。

如果需要的话,您必须在第一个触发器中重复 col3 的分配。对于无论您点击任一触发器都希望发生的更复杂的副作用,您可以有一个过程来执行任何必要的操作(不影响此 table),然后从两个触发器调用它。不过,如果 DML 更新触及两列,那么您需要一种机制来确保该过程不会被调用两次 - 导致两个触发器都触发。