我试图创建一个触发器,将子表的值(插入或更新后)聚合到父表。
子表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
。
谢谢!
答案 0 :(得分:1)
错误来自于您查询变异表C.
变异表是由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
,因为您在C
表SELECT ... 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