我正面临变异触发错误,
我将在这里描述这个问题 我正在使用tableA和tableB。
TableA包含一个名为empChecked的列,它可以包含2个值' - ','+' TableB包含一个名为mgrChecked的列,它可以包含2个值' - ','+'。
当前要求是empChecked中的两个字段,并且mgrchecked必须同步。我的意思是如果empChecked更新为'+',那么在tableB中检查的mgr必须更新为'+',反之亦然。两个字段都可以从前端进行更新。
我在两个表上都创建了触发器。但我面临ora-04091错误。
请建议我采取任何方法来实现这一目标?
答案 0 :(得分:4)
变异表错误是代码气味。它几乎总是指向一个糟糕的数据模型,通常标准化不足。
当然,这里有一个糟糕的数据模型。您在表上有一个列有两个设置。没关系。现在,您希望将同一列添加到第二个表中,并使两者保持同步。这个新专栏完全没有意义。新列中没有可用的信息,而不是查询第一个表。
这就是ORA-04091告诉你的。你可以花费大量的时间来构建一个变通方法,但这都会浪费精力。
答案 1 :(得分:1)
为什么不创建视图,而不是使用触发器进行这种同步 名为TableB,它将“包含”来自TableA的TableB(非mgrchecked)+ empChecked列的所有数据 像这样的东西
create or replace view TAbleB as
select t1.id
, t1.Column2
, ...
, t1.ColumnN
, t.empChecked
from TableA t
, TableB t1
where t.id = t1.id
答案 2 :(得分:-1)
你对细节有点不清楚,但我认为这会有所帮助(假设你在两张桌子上都有一个ID列)
CREATE TRIGGER tri_table_a
AFTER UPDATE ON table_a
DECLARE
hits NUMBER :=0;
BEGIN
SELECT count(*) INTO hits FROM table_a a INNER JOIN table_b b ON (a.id=b.id) WHERE a.emp_checked<>b.mgr_checked;
IF hits>0 THEN
UPDATE table_b b SET mgr_checked=(SELECT emp_checked FROM table_a a WHERE a.id=b.id);
END IF;
END;
/
CREATE TRIGGER tri_table_b
AFTER UPDATE ON table_b
DECLARE
hits NUMBER :=0;
BEGIN
SELECT count(*) INTO hits FROM table_a a INNER JOIN table_b b ON (a.id=b.id) WHERE a.emp_checked<>b.mgr_checked;
IF hits>0 THEN
UPDATE table_a a SET emp_checked=(SELECT mgr_checked FROM table_b b WHERE a.id=b.id);
END IF;
END;
/
关键是不要使用FOR EACH ROW
,这会导致表锁定。
修改强>
这将 NOT 与表锁或ORA-04091冲突,因为触发条件中没有FOR EACH ROW
(又名行触发器) ,这意味着触发器主体只会在整个更新动作完成后执行 AFTER ;
这将 NOT 导致无限循环,因为当触发器主体中的count(*)
返回0时,UPDATE
内部触发器主体将不会被执行;
此外,必须使用count(*)
,因为这是一个语句触发器,并且没有:new.emp_checked
可用;
一般情况:更新table_a - &gt;触发tri_table_a - &gt; [触发]检查计数 - &gt; [触发]更新table_b - &gt;触发tri_table_b - &gt; [触发]检查计数 - &gt;完成。
在发布此答案之前,我自己试了一下。