vir*_*bee 5 oracle plsql database-trigger
我正在使用 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
Run Code Online (Sandbox Code Playgroud)
插入行后,我执行更新。我希望 COL1="now we will see", COL2="only testing" and COL3 = "trigger_test_2 has fire"。
update TRIGGER_TEST set COL1 = 'now we will see';
Run Code Online (Sandbox Code Playgroud)
但我得到的是:
select * from TRIGGER_TEST;
COL1 COL2 COL3
----------------------------------------------------------------
now we will see only testing 1_col3
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释一下吗?我真的很确定,对于以前的 ORACLE 版本,这个 szenario 已经奏效了。但现在没有了。
我非常确定,在以前的 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
Run Code Online (Sandbox Code Playgroud)
这before update of COL2 on TRIGGER_TEST是一个DML 事件子句。您正在创建简单的 DML 触发器:
DML 触发器在表或视图上创建,其触发事件由 DML 语句 DELETE、INSERT 和 UPDATE 组成。...
当您发出更新时,DML 会导致第一个触发器触发。但是当您在该触发器内分配新值时:
:new.col2 := 'only testing';
Run Code Online (Sandbox Code Playgroud)
..这不是DML语句 - 它不是单独的更新。
如果以这种方式分配值确实导致触发器触发,那么如果您这样做:
:new.col1 := 'something';
Run Code Online (Sandbox Code Playgroud)
...然后第一个触发器将再次递归地触发,直到遇到错误ORA-00036: maximum number of recursive SQL levels (50) exceeded。那显然会很糟糕。
col3如果您需要这样做,则必须在第一个触发器中重复分配。对于无论您点击任一触发器都希望发生的更复杂的副作用,您可以有一个过程来执行任何必要的操作(不影响此表),然后从两个触发器调用该操作。不过,您需要一种机制来确保在 DML 更新触及两列时该过程不会被调用两次 - 这将导致两个触发器都触发。