为什么我没有在触发器中收到变异表错误?

Cen*_*ion 11 trigger oracle oracle-11g

众所周知(或至少是)您不能在触发器内的变异表上使用 DML 语句。Oracle 文档的摘录:

变异表是由 UPDATE、DELETE 或 INSERT 语句修改的表,或者可能受 DELETE CASCADE 约束影响更新的表。

发出触发语句的会话不能查询或修改变异表。此限制可防止触发器看到一组不一致的数据。

但是,当我执行insert into empusing SQL Developer 或 SQL*Plus时,我不明白为什么这个演示触发器不会因“变异表”错误而失败:

CREATE OR REPLACE TRIGGER emp_bri   
  BEFORE INSERT ON emp 
    FOR EACH ROW
BEGIN

  SELECT max(id) + 1 INTO :NEW.id FROM emp;
  UPDATE emp SET salary = 5000;

END emp_bri;
Run Code Online (Sandbox Code Playgroud)

插入成功完成下一个id值并更新所有emp记录。我使用的是 Oracle 数据库 11g 企业版 11.2.0.1.0 版。我已阅读有关复合触发器的信息,但示例并未使用它们。

Nic*_*nov 12

有一个例外。在before insert表上定义行级触发器并发出单行INSERT语句时,table is mutating不会引发错误。但是如果定义同一种触发器并发出多行INSERT语句,则会引发错误。下面是一个例子:

SQL> create table TB_TR_TEST(
  2    col1 number,
  3    col2 number
  4  )
  5  ;

Table created

SQL> create or replace trigger TR_TB_TR_TEST
  2  before insert on TB_TR_TEST
  3  for each row
  4  begin
  5    SELECT max(col1) + 1 INTO :NEW.col1
  6      FROM TB_TR_TEST;
  7    UPDATE TB_TR_TEST SET col2 = 5000;
  8  end;
  9  /

Trigger created
Run Code Online (Sandbox Code Playgroud)

这是一个单行insert语句,它不会引发变异表错误:

SQL> insert into TB_TR_TEST(col1, col2) values(1,2);

1 row inserted

SQL> insert into TB_TR_TEST(col1, col2) values(3,5);

1 row inserted

SQL> commit;

Commit complete
Run Code Online (Sandbox Code Playgroud)

这是一个多行插入语句,它会引发变异表错误:

SQL> insert into TB_TR_TEST(col1, col2)
  2    select 1, 2
  3      from dual;

insert into TB_TR_TEST(col1, col2)
  select 1, 2
    from dual

ORA-04091: table HR.TB_TR_TEST is mutating, trigger/function may not see it
ORA-06512: at "HR.TR_TB_TR_TEST", line 2
ORA-04088: error during execution of trigger 'HR.TR_TB_TR_TEST'
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。有趣的是,这个异常似乎只记录在 8i (!) 手册中:http://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/01_13dbt.htm#376(“*”部分变异和约束表*") 我在当前的手册中找不到该语句。 (2认同)