1

我正在尝试创建一个触发器,它将子表的值(插入或更新后)聚合到父表。子表C具有字段,id, year, month, value而父表具有. 当向 C 插入新行或更新现有行时,触发器应将该年的所有月份值求和,并将总和写入. 这是我实现它的方式:Pid, year, valueP

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。谢谢!

4

3 回答 3

1

该错误来自您正在查询变异表 C的事实。

文档

变异表是由 UPDATE、DELETE 或 INSERT 语句修改的表,或者可能会因 DELETE CASCADE 约束的影响而更新的表。

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

您可以阅读这篇文章,其中展示了如何避免该错误。

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

于 2012-09-17T07:05:42.427 回答
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 的语法,也许它需要一些其他子句。

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

CREATE MATERIALIZED VIEW LOG ON C WITH SEQUENCE, ROWID
(id, year, value)
INCLUDING NEW VALUES;
于 2012-09-17T07:06:23.650 回答
1

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

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 
于 2012-09-17T07:44:21.823 回答