Oracle触发器 - 从子表到父表

时间:2012-09-17 06:46:24

标签: c# .net database oracle plsql

我试图创建一个触发器,将子表的值(插入或更新后)聚合到父表。 子表C包含字段id, year, month, value,父P - id, year, value。 当向C插入新行或更新现有的行时,触发器应该汇总该年的所有月份值,并将总和写入P中的相应行。 以下是我如何实施它:

CREATE OR REPLACE
TRIGGER tr__aggregation 
AFTER INSERT OR UPDATE ON C
FOR each row 
DECLARE

BEGIN


 MERGE INTO P o
            USING (SELECT id, year, sum(value) as val
                  FROM C 
                   WHERE id = :NEW.id
                   AND year = :NEW.year
                   GROUP BY id, year) n 
            ON (n.id = o.id AND n.year = o.year)
            WHEN NOT MATCHED THEN INSERT (o.id, o.year, o.value) 
                                  VALUES (n.id, n.year, n.value)
            WHEN MATCHED THEN UPDATE SET o.value = NVL(n.value, o.value);

EXCEPTION WHEN OTHERS THEN
    pck_util.pr_exception_info(TRUE);
    RAISE;
END;

出于某种原因,我收到此错误: SQL Error: ORA-04091: table C is mutating, trigger/function may not see it

我不明白为什么,我不是试图修改C,而只是P。 谢谢!

3 个答案:

答案 0 :(得分:1)

错误来自于您查询变异表C.

来自documentation

  

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

     

发出触发语句的会话无法查询或   修改变异表。

您可以阅读此article,其中显示了如何避免错误。

我个人会使用物化视图来存储聚合。

答案 1 :(得分:1)

这是因为您使用C中的选择来更新P,这只是移动(变异)。

更好的解决方案是使用物化视图:

Create materialized view p
refresh fast on commit as
SELECT id, year, sum(value) as val
FROM C 
GROUP BY id, year;

我不知道fly的语法,也许还需要其他一些条款。

更新:只需阅读docs,您还需要基表上的物化视图日志,如示例3所示:

CREATE MATERIALIZED VIEW LOG ON C WITH SEQUENCE, ROWID
(id, year, value)
INCLUDING NEW VALUES;

答案 2 :(得分:1)

您正面临该错误SQL Error: ORA-04091: table C is mutating, trigger/function may not see it,因为您在CSELECT ... FROM C正在修改AFTER INSERT OR UPDATE ON C时进行查询。要解决这种错误,您只需将触发器的逻辑封装在一个过程中,并在需要时执行它。您还可以创建一个视图,该视图将替换您的P表。

Create or replace view P as
  select p.id
       , p.year
       , sum(nvl(c.value, 0)) value
    from P
    join C
      on (p.id = c.id and p.year = c.year)
   group by p.id
          , p.year