【问题标题】:Oracle SQL Developer Mutating tables and TriggersOracle SQL Developer 变异表和触发器
【发布时间】:2015-01-29 04:38:35
【问题描述】:

我正在为我的大学科目制作一个小项目,但在为我的小型数据库在 Oracle SQL Developer 中设计触发器时遇到了问题。

我有以下表格:

create table ASSIGNED_TO(
  ASSIGNMENT_ID int not null primary key,
  ROOM_ID int not null,
  foreign key (ROOM_ID) references ROOM(ROOM_ID),
  NURSE_ID int not null,
  foreign key (NURSE_ID) references NURSE(PERSON_ID)
);

create table MESSAGE_LOG(
  ID int not null,
  MESSAGE varchar2(100) null
);

每次ASSIGNED_TO 表中的一行被INSERTUPDATE 操作更改并且有2 行具有相同的ROOM_ID 我希望触发器将一条简单消息写入MESSAGE_LOG 表。

导致我出现问题的是表ASSIGNED_TO 的“变异”。我目前的解决方案是:

create or replace TRIGGER TRIG3
  AFTER INSERT OR UPDATE
  ON ASSIGNED_TO
  FOR EACH ROW
DECLARE
  nr_nurses INTEGER;  
BEGIN
      SELECT COUNT(*) INTO nr_nurses
        FROM ASSIGNED_TO
      WHERE ROOM_ID = :NEW.ROOM_ID;

      IF nr_nurses >= 2 THEN
        INSERT INTO MESSAGE_LOG values (3, '2 or more nurses per room detected');
        DBMS_OUTPUT.PUT_LINE('3| 2 or more nurses per room detected');
      END IF;
END;

这个触发器给了我“变异表”错误,到目前为止我一直无法修复它。使用:OLD.ROOM_ID 而不是ROOM_ID 失败,因为:OLD.ROOM_IDUPDATE 操作的情况下不存在。任何有关使这项工作的建议表示赞赏。

【问题讨论】:

    标签: sql oracle database-trigger


    【解决方案1】:

    正如@MichaelBroughton 所指出的,你不能在这里使用行触发器,因为你会得到可怕的“变异表”异常。有多种方法可以解决此问题;也许最简单的方法是使用语句触发器来完成相同的目标。将您的触发器修改为:

    CREATE OR REPLACE TRIGGER TRIG3
      AFTER INSERT OR UPDATE
      ON ASSIGNED_TO
    BEGIN
      -- The following cursor will only find rows for
      -- which multiple nurses have been assigned.
    
      FOR aRow IN (SELECT ROOM_ID, COUNT(*) AS NURSE_COUNT
                     FROM ASSIGNED_TO
                     GROUP BY ROOM_ID
                     HAVING COUNT(*) >= 2)
      LOOP
        INSERT INTO MESSAGE_LOG
          (ID, MESSAGE)
        VALUES
          (3, aRow.NURSE_COUNT || 'ASSIGNED TO ROOM ' || aRow.ROOM_ID);
    
        DBMS_OUTPUT.PUT_LINE('3| ' || aRow.NURSE_COUNT || 'ASSIGNED TO ROOM ' ||
                             aRow.ROOM_ID);
      END LOOP;
    END TRIG3;
    

    注意:这是一个语句触发器,因为它不包括行 FOR EACH ROW

    对于影响 ASSIGNED_TO 表的每个 INSERT 或 UPDATE 语句,该触发器将被调用一次,而不是为每一行更改一次,但这样做触发器将提供与原始行触发器相同的功能,并且不会受到“变异表”问题。

    分享和享受。

    【讨论】:

    • 是的,尽管这只会带来新的问题,例如在这种情况下,所有先前触发此条件的插入都将在每次插入或更新表时重新找到并重新记录,所以你需要添加对 message_log 的检查,以确保您不会一遍又一遍地重新记录相同的问题。并且使用语句级触发器来解决行级操作的效率非常低!不是说行不通。但是如果可以避免的话,这是一种糟糕的编程风格。
    • 我的目标是使用触发器,我了解此解决方案的优缺点。此代码适用于我的目的。谢谢!
    【解决方案2】:

    引用您要插入的表会导致此问题,因为您正在询问表的内容,因为它正在更改,但在该更改提交之前。

    答案是不要通过触发器进行此检查。我更喜欢访问 pl/sql 业务级接口,而不是来自 UI 的纯表交互。例如,编写一个 insert_room_assigment(nurse_id, room_id) 过程,该过程执行插入、检查,并在必要时记录问题,或者可以先检查但一开始就不允许插入。

    但是无论你如何解决它 - 触发器都不起作用。

    【讨论】:

    • 这真的很好听,因为我可以将注意力集中在可能有用的东西上。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    相关资源
    最近更新 更多