2012-09-17 121 views
1

我試圖創建一個觸發器,它可以將父表的值(在插入或更新後)聚合到父表中。 子表C有字段id, year, month, value,父母P - id, year, value。 當一個新行插入到C中或更新了現有行時,觸發器應累計該年的所有月份值,並將總和寫入P中的相應行。 這裏是我是如何實現它:Oracle觸發器 - 從子表到父項

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

我不明白爲什麼,我並不想modifiy C,只有P。 謝謝!

+0

可能出現[Oracle中的突變觸發器問題]的副本(http://stackoverflow.com/questions/12346591/mutating-trigger-issue-in-oracle) – APC

回答

1

誤差來自這樣的事實,你是查詢的變異表C.

documentation

甲變異表是由一個UPDATE修改的表, DELETE ,或INSERT語句或可能由DELETE CASCADE約束的 效果更新的表。

發出觸發語句的會話無法查詢或者 修改了一個變異表。

您可以閱讀這個article,它顯示瞭如何避免錯誤。

我個人會使用物化視圖來存儲聚合。

1

這是因爲你使用C中的選擇來更新P,C正在移動(變異)。

一個更好的解決方案是使用物化視圖:粉煤灰

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

我不知道語法,也許它需要一些其他條款。

更新:剛纔看了docs,你還需要在基表中的物化視圖日誌,如實施例3:

CREATE MATERIALIZED VIEW LOG ON C WITH SEQUENCE, ROWID 
(id, year, value) 
INCLUDING NEW VALUES; 
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