在oracle中突变触发器问题

时间:2012-09-10 06:48:46

标签: sql oracle plsql oracle11g

我正面临变异触发错误,

我将在这里描述这个问题 我正在使用tableA和tableB。

TableA包含一个名为empChecked的列,它可以包含2个值' - ','+' TableB包含一个名为mgrChecked的列,它可以包含2个值' - ','+'。

当前要求是empChecked中的两个字段,并且mgrchecked必须同步。我的意思是如果empChecked更新为'+',那么在tableB中检查的mgr必须更新为'+',反之亦然。两个字段都可以从前端进行更新。

我在两个表上都创建了触发器。但我面临ora-04091错误。

请建议我采取任何方法来实现这一目标?

3 个答案:

答案 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;完成。

  • 在发布此答案之前,我自己试了一下。