想象一下 Oracle 19 中的以下场景:
表A 表B
表 B 有一个复合触发器 TB_TRG,用于读取表 A(在语句后触发的过程)。
表 A 有一个更新表 B 的触发器(因此触发 TB_TRG)。
我收到变异表 A 错误。因为我在 AFTER STATEMENT 调用中读取表 A,难道不应该避免吗?
谢谢
我构建了一个复合触发器,它在从 after 语句子句调用的过程中读取表 A。变异错误仍然存在。
CREATE TABLE "DEPT"
("DEPTNO" NUMBER(2,0),
"DNAME" VARCHAR2(14),
"LOC" VARCHAR2(13),
"SAL_FACTOR" NUMBER(4,0)
);
CREATE UNIQUE INDEX "SYS_C0031557" ON "DEPT" ("DEPTNO")
;
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;
ALTER TABLE "DEPT" ADD PRIMARY KEY ("DEPTNO")
USING INDEX ENABLE;
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)
);
CREATE UNIQUE INDEX "SYS_C0031556" ON "EMP" ("EMPNO")
;
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;
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;
ALTER TABLE "EMP" MODIFY ("EMPNO" NOT NULL ENABLE);
ALTER TABLE "EMP" ADD PRIMARY KEY ("EMPNO")
USING INDEX ENABLE;
ALTER TABLE "EMP" ADD FOREIGN KEY ("DEPTNO")
REFERENCES "DEPT" ("DEPTNO") ENABLE;
ALTER TABLE "EMP" ADD FOREIGN KEY ("MGR")
REFERENCES "EMP" ("EMPNO") ENABLE;
如果触发器 A 更新 B 并且触发器 B 尝试从 A 读取数据,您将收到变异错误。在触发器的上下文中,您无法从该执行范围内正在修改的表(原始行更新操作)中读取数据,因为 A 正在被修改,因此处于中间状态。您必须从触发器 B 中删除表 A 的查询。