2011-12-12 131 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