插入触发器后发生变异错误

时间:2011-12-12 12:58:04

标签: oracle plsql

以下代码给出了一个变异错误。 任何人都可以帮助解决这个问题。

    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;
    /

2 个答案:

答案 0 :(得分: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;
/

编辑 Rajesh提到,在插入新行之前,OP希望更新aso_quote_headers_all表中的所有其他记录。

嗯,这是可行的,但这有点棘手。要正确执行此操作,您需要

  1. pl / sql包和包头中由触发器修改的变量。该变量可以是包含新插入记录的ID的列表。插入触发器后的行级别将向列表中添加新ID。对于每个不同的会话,此包变量的内容将有所不同,因此我们将此变量称为session_variable
  2. 插入触发器后的行级别,会向session_variable添加新ID。
  3. 插入触发器后的表级别,它将从session_variable获取ID,处理ID,然后将其从session_variable中删除。此触发器可以在aso_quote_headers_all上执行必要的选择/更新。处理完新插入的ID后,此触发器应确保将其从session_variable中删除。

答案 1 :(得分:3)

我意识到你现在必须解决了你的问题。但是,我在下面添加这个答案,以帮助其他任何面临类似问题的人,就像你和我一样。

我最近遇到了变异表(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. 首先是在我们捕获新插入行的rowid的每个行之后
  2. 接下来是AFTER STATEMENT,我们在WHERE子句中使用rowid(在第一个事件中捕获)更新表。
  3. 如果您想了解有关复合触发器的更多信息,请使用有用的link