ORA-04091 由于游标,表名在触发器中发生变化

Posted

技术标签:

【中文标题】ORA-04091 由于游标,表名在触发器中发生变化【英文标题】:ORA-04091 table name is mutating in trigger due to cursor 【发布时间】:2014-01-03 19:22:25 【问题描述】:

因此,当我编译以下脚本时,它会引发变异表错误:

CREATE OR REPLACE TRIGGER SEND_MAIL
BEFORE DELETE
ON CATEGORIE
FOR EACH ROW
DECLARE 
bodytext  varchar2(100);

CURSOR getabonnee IS
SELECT CATEGORIEABONNEMENT.MAILABONNEEID, NAAM 
FROM CATEGORIE
INNER JOIN CATEGORIEABONNEMENT ON CATEGORIEABONNEMENT.CATEGORIENAAM = CATEGORIE.NAAM
WHERE NAAM = :old.NAAM;

CURSOR getabonneeinfo(p_id CATEGORIEABONNEMENT.MAILABONNEEID%TYPE) IS
SELECT MAILABONNEE.VOORNAAM, MAILABONNEE.ACHTERNAAM, MAILABONNEE.EMAILADRES
FROM CATEGORIEABONNEMENT
INNER JOIN MAILABONNEE ON MAILABONNEE.ID = CATEGORIEABONNEMENT.MAILABONNEEID
WHERE MAILABONNEEID = p_id;

BEGIN

   FOR cc IN getabonnee LOOP

      FOR cc2 IN getabonneeinfo(cc.MAILABONNEEID) LOOP

     bodytext := cc2.voornaam || cc2.achternaam || :old.NAAM;
     EXECUTE IMMEDIATE bodytext;

     SENDMAILABONNEE(bodytext, cc2.emailadres);

     DELETE FROM CATEGORIEABONNEMENT
     WHERE MAILABONNEEID = cc.MAILABONNEEID;

     UPDATE NIEUWSBERICHT
     SET CATEGORIENAAM = null
     WHERE CATEGORIENAAM = :old.NAAM;

  END LOOP;
END LOOP;
END;
/

savepoint deletecategory;

delete from Categorie where naam='Buitenland';

rollback to deletecategory;

我寻找此错误的解决方案,发现人们建议使用复合触发器。问题是由于某种原因,我的数据库软件 (Oracle SQL Developer) 无法将复合触发器识别为有效单元。我检查了我的 oracle 版本,我有 11g,所以我不太明白为什么它不起作用。有人有这个问题的解决方案吗?

【问题讨论】:

所以,您一定遇到了某种编译错误。请更具体。 这不是无限循环吗?在您的Delete from Categorie where naam='Buitenland' from categorie 的触发器中,触发器用于删除之前的表类别。我相信系统会在更新之前递归调用触发器,从而进入无限循环。但是我对触发器的了解很薄弱。只是看起来像一个逻辑缺陷。 @OldProgrammer 当我使用复合触发器时,它会抛出错误 PLS-00103:在期望以下之一时遇到符号“FOR”:函数、编译指示、过程、之前、之后等。编译上面代码的错误是 ORA-04091: table name is mutating, trigger/function may not see it. “Oracle SQL Developer”不是您的数据库软件——它只是 Oracle RDBMS 的接口。可能您使用的 RDBMS 版本不支持复合触发器。 不要从触发器所在的同一个表中选择/更新/删除,因为它处于更改状态,因此是“变异”。 【参考方案1】:

在您的第一个游标中,不要在查询中包含 CATEGORIE 表。触发器已经具有您要删除的行中所有列的值,因此将其更改为:

SELECT MAILABONNEEID 
  FROM CATEGORIEABONNEMENT
 WHERE CATEGORIEABONNEMENT.CATEGORIENAAM = :old.NAAM;

【讨论】:

以上是关于ORA-04091 由于游标,表名在触发器中发生变化的主要内容,如果未能解决你的问题,请参考以下文章

ORA-04091: 表名正在变异

ORA-04091“更新后”触发器错误,如何解决?

oracle 触发器 ORA-04091

ORA-04091: 表 JOSEP.EMP 正在变异,触发器/函数可能看不到它

ora-04091 表正在变异-

ORA-04091:表正在变异,触发器/函数可能看不到它,ORA-06512:,ORA-06512:在“SYS.DBMS_SQL”,第 1721 行