我正在为我的大学科目制作一个小项目,我在为小型数据库设计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
中的一行被INSERT
或UPDATE
操作更改,并且有两行具有相同的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_ID
失败,因为UPDATE
不存在。关于做这项工作的任何建议都表示赞赏。
答案 0 :(得分:3)
正如@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语句,将调用此触发器一次,而不是每次更改一行,但这样触发器将提供与原始行触发器相同的功能,并且不会受到影响"变异表"问题
分享并享受。
答案 1 :(得分:1)
引用要插入的表会导致此问题,因为您在更改表时会询问表的内容,但在提交更改之前。
答案是不要通过触发器进行检查。我更喜欢访问pl / sql业务级接口而不是UI中的纯表交互。例如,编写一个insert_room_assigment(nurse_id,room_id)过程来执行插入,检查,并在必要时记录问题,或者可以先检查并且不允许首先插入。
但是你解决了 - 触发器无法正常工作。