为什么在触发器中没有出现变异表错误?


11

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

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

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

但是,我无法理解为什么当我insert into emp使用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;

插入成功完成并显示下一个id值,并更新所有emp记录。我正在使用Oracle Database 11g企业版11.2.0.1.0。我已经阅读了有关复合触发器的信息,但样本未使用它们。


1
无关你的问题,而是:你使用select max(id)分配唯一的编号。只是不要。这是完全不正确的,并且不会扩展。
a_horse_with_no_name 2012年

是的,我知道:)在这种情况下,示例可能不是很好...自动增量值必须通过使用序列和触发器来明确实现。
Centurion

这肯定很奇怪。顺便说一句:这是一个SQLFiddle示例sqlfiddle.com/#!4/9e59f/2
a_horse_with_no_name 2012年

感谢您分享信息,很酷的链接。不知道有这样的Oracle SQL测试网站:)
Centurion

Answers:


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

这是一个单行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

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

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'

这似乎是罪魁祸首。您在手册中对此行为有参考吗?
a_horse_with_no_name 2012年

@a_horse_with_no_name(如果您有权访问support.oracle.com),则搜索ID 132569.1ORA-4091 on BEFORE ROW TRIGGER with INSERT .. into SELECT statement)。
Nicholas Krasnov 2012年

2
谢谢。足够有趣的是,该异常似乎仅记录在8i(!)手册中:docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/…(我可以“ 在“ 更改和约束表 ”部分中)在当前手册中找不到该声明
a_horse_with_no_name 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.