2011-12-12 130 views
2

下面的代碼給出了突變錯誤。 任何1都可以幫助解決這個問題。插入觸發後的突變錯誤

CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger 
    BEFORE INSERT 
    ON aso.aso_quote_headers_all 
    FOR EACH ROW 
    BEGIN 
    UPDATE aso.aso_quote_headers_all 
    SET quote_expiration_date=sysdate+90 
    where quote_header_id=:new.quote_header_id; 
    END; 
    /
+0

你真的需要觸發器嗎?請看http://www.dba-oracle.com/t_avoiding_mutating_table_error。htm –

回答

8

在oracle中有兩個級別的觸發器:行級別和表級別。

行級觸發器被執行for each row。即使語句改變了多於一行,也會爲每個語句執行表級觸發器。
在行級觸發器中,您無法選擇/更新觸發器的表本身:您將得到一個突變錯誤。

在這種情況下,不需要UPDATE語句。剛剛嘗試這一點:

CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger 
BEFORE INSERT 
ON aso.aso_quote_headers_all 
FOR EACH ROW 
BEGIN 
:new.quote_expiration_date=sysdate+90;  
END; 
/

編輯拉傑什提到這是可能的,在插入新行之前,OP想在aso_quote_headers_all表更新所有其他記錄。

嗯,這是可行的,但它有點棘手。要正確執行此操作,您將需要

  1. 一個pl/sql包和包頭中的一個變量,該變量由觸發器修改。這個變量可以是一個包含新插入記錄ID的列表。插入觸發器後的行級別會將新ID添加到列表中。這個包變量的內容對於每個不同的會話都會有所不同,所以我們稱這個變量爲session_variable
  2. 插入觸發後的行級別,這會將新ID添加到session_variable
  3. 插入觸發器後的表級別將從session_variable獲得ID,處理該ID並將其從session_variable中刪除。該觸發器可以在aso_quote_headers_all上執行必要的選擇/更新。在處理新插入的ID後,此觸發器應確保將其從session_variable中移除。
+0

我認爲OP正在試圖在插入一個新的數據庫之前過期數據庫中的現有記錄,而不是修改被插入的行。 –

+0

很可能是這種情況。 @OP? – bpgergo

+0

非常感謝。前插入觸發器工作得很好:) :) – user978417

2

我知道你現在一定已經解決了你的問題。不過,我在下面添加了這個答案,以幫助其他人面對類似的問題。

我最近遇到突變表(ORA-04091:表XXXX都在變異,觸發/功能可能沒看出來)問題,並圍繞搜索之後實現的複合觸發器在11g中可用功能。如果你在11g以下複合觸發器將解決你的問題。

CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger 
FOR INSERT ON aso.aso_quote_headers_all 
COMPOUND TRIGGER 

    row_id rowid; 

    AFTER EACH ROW IS 
    BEGIN 
     row_id := :new.rowid; 
    END AFTER EACH ROW; 

    AFTER STATEMENT IS 
    BEGIN 
     UPDATE aso.aso_quote_headers_all 
     SET quote_expiration_date = sysdate+90 
     WHERE rowid = row_id; 
    END AFTER STATEMENT; 
END aso_quote_cuhk_trigger; 
/

關於它是如何工作的一個詞。該化合物觸發器觸發2個事件:

  1. 首先是EACH ROW我們捕獲新插入行的ROWID AFTER
  2. 接下來是AFTER STATEMENT我們更新使用的rowid的表中WHERE(第一事件期間捕獲的)條款。

如果您想了解有關化合物觸發器的更多信息,請參閱link