当在另一个触发器中更改列时,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 更新触及两列,那么您需要一种机制来确保该过程不会被调用两次 - 会 导致两个触发器都触发。
我正在使用 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 更新触及两列,那么您需要一种机制来确保该过程不会被调用两次 - 会 导致两个触发器都触发。