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

时间:2016-04-19 15:57:32

标签: oracle plsql triggers

所以我必须创建一个触发器,它将对名为'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并将其存储到'logs'表中。

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

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 触发器,我希望更改首先生效,然后触发器会触发插入'logs'表。但相反,我得到了这个错误:

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

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

1 个答案:

答案 0 :(得分:3)

您无法在触发器中查询变异表 看到这个: 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;
/