Oracle SQL 开发人员更改表和触发器
Oracle SQL Developer Mutating tables and Triggers
我正在为我的大学科目做一个小项目,我在 Oracle SQL 小型数据库开发人员中设计触发器时遇到问题。
我有以下 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
);
每次 table ASSIGNED_TO
中的一行被 INSERT
或 UPDATE
操作更改并且有 2 行具有相同的 ROOM_ID
我想要将简单消息写入 MESSAGE_LOG
table.
的触发器
导致我出现问题的是 table ASSIGNED_TO
的 'mutating'。我目前的解决方案是:
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;
这个触发器给我 'Mutating Table' 错误,到目前为止我无法修复它。使用 :OLD.ROOM_ID
而不是 ROOM_ID
失败,因为 :OLD.ROOM_ID
在 UPDATE
操作的情况下不存在。任何关于使这项工作的建议都将受到赞赏。
引用您要插入的 table 会导致此问题,因为您在 table 的内容发生变化时询问其内容,但在提交更改之前。
答案是不要通过触发器执行此检查。我更喜欢访问 pl/sql 业务级接口,而不是来自 UI 的纯 table 交互。例如,编写一个 insert_room_assigment(nurse_id, room_id) 过程来执行插入、检查并在必要时记录问题,或者可以先检查并且不允许插入第一名。
但是无论您如何解决它 - 触发器都不会起作用。
正如@MichaelBroughton 所指出的,您不能在此处使用行触发器,因为您会得到可怕的 "mutating table" 异常。有多种方法可以解决此问题;也许最简单的是使用语句触发器来实现相同的目标。将触发器重做为:
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 table 的每个 INSERT 或 UPDATE 语句,将调用一次此触发器,而不是为更改的每一行调用一次,但这样做触发器将提供与原始行触发器,不会遇到 "mutating table" 问题。
分享和享受。
我正在为我的大学科目做一个小项目,我在 Oracle SQL 小型数据库开发人员中设计触发器时遇到问题。
我有以下 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
);
每次 table ASSIGNED_TO
中的一行被 INSERT
或 UPDATE
操作更改并且有 2 行具有相同的 ROOM_ID
我想要将简单消息写入 MESSAGE_LOG
table.
导致我出现问题的是 table ASSIGNED_TO
的 'mutating'。我目前的解决方案是:
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;
这个触发器给我 'Mutating Table' 错误,到目前为止我无法修复它。使用 :OLD.ROOM_ID
而不是 ROOM_ID
失败,因为 :OLD.ROOM_ID
在 UPDATE
操作的情况下不存在。任何关于使这项工作的建议都将受到赞赏。
引用您要插入的 table 会导致此问题,因为您在 table 的内容发生变化时询问其内容,但在提交更改之前。
答案是不要通过触发器执行此检查。我更喜欢访问 pl/sql 业务级接口,而不是来自 UI 的纯 table 交互。例如,编写一个 insert_room_assigment(nurse_id, room_id) 过程来执行插入、检查并在必要时记录问题,或者可以先检查并且不允许插入第一名。
但是无论您如何解决它 - 触发器都不会起作用。
正如@MichaelBroughton 所指出的,您不能在此处使用行触发器,因为您会得到可怕的 "mutating table" 异常。有多种方法可以解决此问题;也许最简单的是使用语句触发器来实现相同的目标。将触发器重做为:
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 table 的每个 INSERT 或 UPDATE 语句,将调用一次此触发器,而不是为更改的每一行调用一次,但这样做触发器将提供与原始行触发器,不会遇到 "mutating table" 问题。
分享和享受。