【问题标题】:ORACLE "before update" trigger does not fire when column is changed within another trigger在另一个触发器中更改列时,ORACLE“更新前”触发器不会触发
【发布时间】:2017-11-08 19:51:27
【问题描述】:

我正在使用 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="only testing" 和 COL3 = "trigger_test_2 has fire"。

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 版本,这个场景已经奏效了。但现在不行了。

【问题讨论】:

  • 欢迎来到 SO!这是你的第一个问题,它写得很好,标题有意义,标签正确,格式很好;它甚至显示你做了什么,并允许人们重现测试。 +1 !
  • .. 如果您想继续以正确的方式使用 SO,here 您会发现有人回答您时该怎么做。

标签: oracle plsql database-trigger


【解决方案1】:

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

【讨论】:

    【解决方案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_TESTDML event clause。你正在创建simple DML triggers

    在表或视图上创建 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 更新触及两列时不会调用该过程两次 - 这导致两个触发器都被触发。

    【讨论】:

    • 非常感谢您的解释!现在我明白为什么它不起作用了.....
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    • 2021-09-08
    • 2016-06-24
    相关资源
    最近更新 更多