【问题标题】:ORA-04091: table xx_xx is mutating, trigger/function may not see itORA-04091: 表 xx_xx 正在变异,触发器/函数可能看不到它
【发布时间】:2016-08-11 22:31:42
【问题描述】:

所以我必须创建一个触发器,它将对名为“passengerlist1”的表所做的更改记录到一个名为“logs”的额外表中。

日志表:

create table logs (
  p_name varchar(255),
  p_surname varchar(255),
  f_id number,
  time_stamp timestamp
);

Passengerlist1 表具有以下属性:FLIGHTID、PERSONID、SEATNUMBER。

还有一个名为 PERSON1 的表,其属性为:PERSONID、GIVENNAME、FAMILYNAME、DATEOFBIRTH。 这是我需要从中选择一个人的名字和姓氏并将其存储到'logs' 表以防对 'passengerlist1' 表进行更改。从“passengerlist1”表中,我只需要选择 FLIGHTID 并将其存储到“日志”表中。

因此,这就是我的触发器:

CREATE OR REPLACE TRIGGER log_changes 
  AFTER INSERT OR UPDATE OR DELETE
  ON passengerlist1
  FOR EACH ROW

DECLARE
 t_name varchar2(255);
 t_surname varchar2(255);
BEGIN
  BEGIN

   IF DELETING THEN
    SELECT PERSON1.GIVENNAME INTO T_NAME FROM 
      PERSON1 JOIN PASSENGERLIST1 
      ON PERSON1.PERSONID = PASSENGERLIST1.PERSONID
      WHERE PASSENGERLIST1.FLIGHTID = :OLD.FLIGHTID;

    SELECT PERSON1.FAMILYNAME INTO T_SURNAME FROM 
      PERSON1 JOIN PASSENGERLIST1 
      ON PERSON1.PERSONID = PASSENGERLIST1.PERSONID
      WHERE PASSENGERLIST1.FLIGHTID = :OLD.FLIGHTID;

    INSERT INTO LOGS VALUES (T_NAME, T_SURNAME, :OLD.FLIGHTID, SYSDATE);
   END IF;

   IF UPDATING THEN

    SELECT PERSON1.GIVENNAME INTO T_NAME FROM 
      PERSON1 JOIN PASSENGERLIST1 
      ON PERSON1.PERSONID = PASSENGERLIST1.PERSONID
      WHERE PASSENGERLIST1.FLIGHTID = :NEW.FLIGHTID;

     SELECT PERSON1.FAMILYNAME INTO T_SURNAME FROM 
      PERSON1 JOIN PASSENGERLIST1 
      ON PERSON1.PERSONID = PASSENGERLIST1.PERSONID
      WHERE PASSENGERLIST1.FLIGHTID = :NEW.FLIGHTID;

    INSERT INTO LOGS VALUES (T_NAME, T_SURNAME, :NEW.FLIGHTID, SYSDATE);
   END IF;

   IF INSERTING THEN
      SELECT PERSON1.GIVENNAME INTO T_NAME FROM 
      PERSON1 JOIN PASSENGERLIST1 
      ON PERSON1.PERSONID = PASSENGERLIST1.PERSONID
      WHERE PASSENGERLIST1.FLIGHTID = :NEW.FLIGHTID;

     SELECT PERSON1.FAMILYNAME INTO T_SURNAME FROM 
      PERSON1 JOIN PASSENGERLIST1 
      ON PERSON1.PERSONID = PASSENGERLIST1.PERSONID
      WHERE PASSENGERLIST1.FLIGHTID = :NEW.FLIGHTID;

      INSERT INTO LOGS VALUES (T_NAME, T_SURNAME, :NEW.FLIGHTID, SYSDATE);
   END IF;
END;
END;
/

现在使用以下匿名块:

begin
 delete from passengerlist1 where flightid = 1;
end;
/

要对passengerlist1 表进行一些更改,因为我将此触发器定义为AFTER 触发器,我希望更改首先生效,然后触发器将触发插入到“日志”中桌子。但是我得到了这个错误:

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

我做错了什么?提前谢谢你。

【问题讨论】:

    标签: oracle plsql triggers


    【解决方案1】:

    您无法在触发器中查询变异表。
    看到这个: https://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm

    对变异表的触发限制

    变异表是被 UPDATE 修改的表, DELETE 或 INSERT 语句,或可能由 DELETE CASCADE 约束的影响。

    发出触发语句的会话无法查询或 修改变异表。此限制可防止触发器 看到一组不一致的数据。

    此限制适用于所有使用 FOR EACH ROW 的触发器 条款。不考虑在 INSTEAD OF 触发器中修改的视图 变异。

    当触发器遇到变异表时,会发生运行时错误, 触发体和触发语句的效果滚动 返回,并将控制权返回给用户或应用程序。

    试试这个代码:

    create or replace 
    TRIGGER log_changes 
      AFTER INSERT OR UPDATE OR DELETE
      ON passengerlist1
      FOR EACH ROW
    
    DECLARE
     t_name varchar2(255);
     t_surname varchar2(255);
    BEGIN
       IF DELETING THEN
        SELECT PERSON1.GIVENNAME, PERSON1.FAMILYNAME INTO T_NAME,  T_SURNAME
        FROM PERSON1
        WHERE PERSON1.PERSONID = :OLD.PERSONID;
    
        INSERT INTO LOGS VALUES (T_NAME, T_SURNAME, :OLD.FLIGHTID, SYSDATE);
       END IF;
    
       IF UPDATING OR INSERTING THEN
    
         SELECT PERSON1.GIVENNAME,  PERSON1.FAMILYNAME  INTO T_NAME, T_SURNAME 
         FROM PERSON1 
         WHERE PERSON1.PERSONID = :NEW.PERSONID;
    
         INSERT INTO LOGS VALUES (T_NAME, T_SURNAME, :NEW.FLIGHTID, SYSDATE);
       END IF;
    END;
    /
    

    【讨论】:

      猜你喜欢
      • 2015-06-28
      • 2010-09-27
      • 2013-11-24
      • 1970-01-01
      • 2022-10-20
      • 1970-01-01
      • 1970-01-01
      • 2016-04-29
      相关资源
      最近更新 更多