简体   繁体   English

Oracle SQL Developer突变表和触发器

[英]Oracle SQL Developer Mutating tables and Triggers

I am making a small project for my university subject and I have a problem with designing a trigger in Oracle SQL Developer for my small database. 我正在为我的大学科目做一个小型项目,但是在Oracle SQL Developer中为小型数据库设计触发器时遇到问题。

I have the following tables: 我有以下表格:

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

Each time a row from table ASSIGNED_TO is changed by INSERT or UPDATE operation and there are 2 rows with the same ROOM_ID I want the trigger to write a simple message into the MESSAGE_LOG table. 每次通过INSERTUPDATE操作更改表ASSIGNED_TO的一行,并且有2行具有相同的ROOM_ID我希望触发器将一条简单消息写入MESSAGE_LOG表中。

What causes me problems is the 'mutating' of table ASSIGNED_TO . 导致我出现问题的是表ASSIGNED_TO的“变异”。 My current solution is: 我当前的解决方案是:

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;

This trigger gives me 'Mutating Table' error and so far I have been unable to fix it. 此触发器给我“ Mutating Table”错误,到目前为止,我无法修复它。 Using :OLD.ROOM_ID instead of ROOM_ID fails as :OLD.ROOM_ID does not exist in case of UPDATE operation. 使用:OLD.ROOM_ID代替ROOM_ID失败,因为:OLD.ROOM_ID UPDATE操作时不存在。 Any advice on making this work is appreciated. 任何建议使这项工作的赞赏。

As @MichaelBroughton has pointed out, you can't use a row trigger here as you'll get the dreaded "mutating table" exception. 正如@MichaelBroughton指出的那样,您无法在此处使用行触发器,因为您将获得可怕的“变异表”异常。 There are various ways to work around this issue; 有多种方法可以解决此问题。 perhaps the simplest is to use a statement trigger to accomplish the same goal. 也许最简单的方法是使用语句触发器来实现相同的目标。 Rework your trigger as: 将触发器重做为:

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;

Note: this is a statement trigger because it doesn't include the line FOR EACH ROW . 注意:这是一个语句触发器,因为它不包括FOR EACH ROW

This trigger will be invoked once for each INSERT or UPDATE statement which affects the ASSIGNED_TO table instead of once for each row altered, but done this way the trigger will provide the same functionality as the original row trigger and will not suffer from the "mutating table" problem. 对于每个影响ASSIGNED_TO表的INSERT或UPDATE语句,此触发器将被调用一次,而不是为每条被更改的行调用一次,但是这样做,触发器将提供与原始行触发器相同的功能,并且不会遭受“突变表”的影响问题。

Share and enjoy. 分享并享受。

Referencing the table that you are inserting into causes this issue because you are asking about the contents of the table right as it is changing, but before that change is committed. 引用要插入到的表会导致此问题,因为您正在询问表的内容,因为它正在更改,但是在提交更改之前。

The answer is to not do this check through a trigger. 答案是不要通过触发器进行此检查。 I prefer pl/sql business-level interfaces to be accessed rather than pure table interaction from the UI. 我更喜欢访问pl / sql业务级接口,而不是从UI中进行纯表交互。 For example, code an insert_room_assigment(nurse_id, room_id) procedure that does the insert, the check, and the logs the problem if neccessary, or could check first and not allow the insert in the first place. 例如,编写一个insert_room_assigment(nurse_id,room_id)过程的代码,该过程将进行插入,检查,并在必要时记录问题,或者可以首先检查并不允许插入。

But however you solve it - the trigger is NOT going to work. 但是,无论您如何解决,触发器都不会起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM