2012-10-24 61 views
1

我有三個表:A和B 的關係是一個可以有許多乙 所以B具有作爲它的列中的一個到A.id參考讀取當前表ID

Table A 
|id|date|... 

Table B 
|id|A_id|... 

我在表A上創建了一個Oracle觸發器,以便在更新時更新A_Mod表。

這種觸發

CREATE OR REPLACE TRIGGER TR_A_INSERT_UPDATE 
AFTER INSERT OR UPDATE ON A 
FOR EACH ROW 
BEGIN 
    INSERT INTO A_Mod values(..., :new.date, ...) 
END; 

這工作得很好:)

我的問題SI創建表B.觸發

觸發是:

CREATE OR REPLACE TRIGGER TR_B_INSERT_UPDATE 
    AFTER INSERT OR UPDATE ON B 
    FOR EACH ROW 
    DECLARE 
     ts TIMESTAMP; 

    BEGIN 
    SELECT aa.date INTO ts FROM B bb 
     INNER JOIN A aa ON a.id = bb.A_id 
     WHERE bb.id = :new.id; 

     INSERT INTO A_Mod values(..., :new.date, ...) 
    END; 

這觸發正在讀取表B中更新行的ID,然後從通信中獲取日期丁行表A.它然後嘗試將其插入到A_Mod

問題是,我得到一個錯誤突變

Error report: 
SQL Error: ORA-04091: table B is mutating, trigger/function may not see it 
ORA-06512: at "TR_B_INSERT_UPDATE", line 5 
ORA-04088: error during execution of trigger 'TR_B_INSERT_UPDATE' 
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it" 
*Cause: A trigger (or a user defined plsql function that is referenced in 
      this statement) attempted to look at (or modify) a table that was 
      in the middle of being modified by the statement which fired it. 
*Action: Rewrite the trigger (or function) so it does not read that table. 

望着docs我可以通過刪除FOR EACH ROW線和具有消除這種錯誤每聲明觸發一次,而不是每行觸發一次。不幸的是,我使用的是ORM映射器,所以不能控制更新如何發生。我認爲有時候更新可能會覆蓋多行。

該文檔說了一些關於創建一個臨時表,但我不知道這將如何幫助。我需要在觸發器內創建一個臨時表,在這個臨時表上創建一個觸發器,然後更新A_Mod,觸發器被觸發時更新這個臨時表,然後刪除所有內容?

任何提示非常感謝。

感謝

回答

2

它不會出現有任何理由在你的扳機上B查詢B表。你應該能夠簡單地使用:new.a_id

CREATE OR REPLACE TRIGGER TR_B_INSERT_UPDATE 
    AFTER INSERT OR UPDATE ON B 
    FOR EACH ROW 
DECLARE 
    ts TIMESTAMP; 
BEGIN 
    SELECT a.date 
    INTO ts 
    FROM A a 
    WHERE a.id = :new.a_id; 

    INSERT INTO A_Mod values(..., :new.date, ...) 
END; 

從數據建模的角度來看查詢A,不過,我會感到非常擔心,如果在需要的子表觸發從父表查詢任何信息或插入數據放入父表寫入的相同歷史記錄表中。這似乎可能表明正常化問題。

+0

很好用 - 謝謝! – RNJ