语句触发器后发生变异表错误。为什么?

问题描述 投票:0回答:1

想象一下 Oracle 19 中的以下场景:

表A 表B

表 B 有一个复合触发器 TB_TRG,用于读取表 A(在语句后触发的过程)。

表 A 有一个更新表 B 的触发器(因此触发 TB_TRG)。

我收到变异表 A 错误。因为我在 AFTER STATEMENT 调用中读取表 A,难道不应该避免吗?

谢谢

我构建了一个复合触发器,它在从 after 语句子句调用的过程中读取表 A。变异错误仍然存在。


-- 表 DEPT 的 DDL

CREATE TABLE "DEPT" 
("DEPTNO" NUMBER(2,0), 
 "DNAME" VARCHAR2(14), 
 "LOC" VARCHAR2(13), 
 "SAL_FACTOR" NUMBER(4,0)
 );

-- 索引 SYS_C0031557 的 DDL

CREATE UNIQUE INDEX "SYS_C0031557" ON "DEPT" ("DEPTNO") 
;

-- 触发器 DEPT_TRG1 的 DDL

CREATE OR REPLACE EDITIONABLE TRIGGER "DEPT_TRG1" 
before insert or update on dept
for each row

begin

if :new.deptno is null then
  select dept_seq.nextval into :new.deptno from sys.dual;
end if;

if :new.sal_factor is not null then
    update emp set new_sal = sal * :new.sal_factor where deptno = :new.deptno;
else
    update emp set new_sal = null where deptno = :new.deptno;
end if;

end;
/
ALTER TRIGGER "DEPT_TRG1" ENABLE;

-- 表 DEPT 的约束

ALTER TABLE "DEPT" ADD PRIMARY KEY ("DEPTNO")
USING INDEX  ENABLE;

-- 表 EMP 的 DDL

CREATE TABLE "EMP" 
("EMPNO" NUMBER(4,0), 
 "ENAME" VARCHAR2(10), 
 "JOB" VARCHAR2(9), 
 "MGR" NUMBER(4,0), 
 "HIREDATE" DATE, 
 "SAL" NUMBER(7,2), 
 "COMM" NUMBER(7,2), 
 "DEPTNO" NUMBER(2,0), 
 "NEW_SAL" NUMBER(7,0), 
 "DEPT_SAL_FACTOR" NUMBER(4,0)
 );

-- 索引 SYS_C0031556 的 DDL

CREATE UNIQUE INDEX "SYS_C0031556" ON "EMP" ("EMPNO") 
;

-- 触发器 EMP_TRG2 的 DDL

CREATE OR REPLACE EDITIONABLE TRIGGER "EMP_TRG2" 
for insert or update on emp
compound trigger
          
deptno# dept.deptno%type;


after each row is

begin

    deptno# := :new.deptno;

end after each row;

after statement is

    factor# number(4);

begin

     select sal_factor
       into factor#
      from dept where deptno = deptno#;

end after statement;
          
end;
/
ALTER TRIGGER "EMP_TRG2" ENABLE;

-- 触发器 EMP_TRG1 的 DDL

CREATE OR REPLACE EDITIONABLE TRIGGER "EMP_TRG1" 
          before insert or update on emp
          for each row
          
          
          begin
              if :new.empno is null then
                  select emp_seq.nextval into :new.empno from sys.dual;
             end if;
             
             
             
             
          end;
/
ALTER TRIGGER "EMP_TRG1" ENABLE;

-- 表 EMP 的约束

ALTER TABLE "EMP" MODIFY ("EMPNO" NOT NULL ENABLE);
ALTER TABLE "EMP" ADD PRIMARY KEY ("EMPNO")
USING INDEX  ENABLE;

-- 表 EMP 的参考约束

ALTER TABLE "EMP" ADD FOREIGN KEY ("DEPTNO")
  REFERENCES "DEPT" ("DEPTNO") ENABLE;
ALTER TABLE "EMP" ADD FOREIGN KEY ("MGR")
  REFERENCES "EMP" ("EMPNO") ENABLE;
oracle triggers mutating-table
1个回答
0
投票

如果触发器 A 更新 B 并且触发器 B 尝试从 A 读取数据,您将收到变异错误。在触发器的上下文中,您无法从该执行范围内正在修改的表(原始行更新操作)中读取数据,因为 A 正在被修改,因此处于中间状态。您必须从触发器 B 中删除表 A 的查询。

© www.soinside.com 2019 - 2024. All rights reserved.