我有两个表,分别称为 DetailRental 和 Video。 VID_NUM是Video的PK和DetailRental的FK。
此代码想要实现的是,当 DetailRental 表中的 Detail_Returndate 或 Detail_Duedate 更改(更新或插入新行)时,触发器将逐行检查 Detail_Returndate 的值。如果其值为空,则视频表中相应的(根据VID_NUM)属性VID_STATUS将更改为“OUT”。
触发器已成功创建。但是,当我想更新日期时。 Oracle 给我错误:
ORA-04091: table SYSTEM2.DETAILRENTAL is mutating, trigger/function may not see it
ORA-06512: at "SYSTEM2.TRG_VIDEORENTAL_UP", line 3
ORA-04088: error during execution of trigger 'SYSTEM2.TRG_VIDEORENTAL_UP'
1. UPDATE DETAILRENTAL
2. SET DETAIL_RETURNDATE = null
3. WHERE RENT_NUM = 1006 AND VID_NUM = 61367
下面是我的代码:
CREATE OR REPLACE TRIGGER trg_videorental_up
AFTER INSERT OR UPDATE OF DETAIL_RETURNDATE, DETAIL_DUEDATE ON DETAILRENTAL
FOR EACH ROW
AS
DECLARE
DTRD DATE;
BEGIN
SELECT DETAIL_RETURNDATE
INTO DTRD
FROM DETAILRENTAL;
IF DTRD IS NULL
THEN UPDATE VIDEO
SET VIDEO.VID_STATUS = 'OUT'
WHERE EXISTS
(SELECT DETAILRENTAL.VID_NUM
FROM DETAILRENTAL
WHERE DETAILRENTAL.VID_NUM = VIDEO.VID_NUM
);
END IF;
END;
非常感谢!
这里解决的问题是代码:
CREATE OR REPLACE TRIGGER trg_videorental_up
AFTER INSERT OR UPDATE OF DETAIL_RETURNDATE, DETAIL_DUEDATE ON DETAILRENTAL
FOR EACH ROW
DECLARE DETAIL_RETURNDATE DATE;
BEGIN
IF :NEW.DETAIL_RETURNDATE IS NULL THEN UPDATE VIDEO SET VID_STATUS = 'OUT' WHERE VID_NUM = :NEW.VID_NUM;
ELSIF :NEW.DETAIL_RETURNDATE > SYSDATE THEN UPDATE VIDEO SET VID_STATUS = 'OUT' WHERE VID_NUM = :NEW.VID_NUM;
ELSIF :NEW.DETAIL_RETURNDATE <= SYSDATE AND TO_CHAR(DETAIL_RETURNDATE)!= '01/01/0001' THEN UPDATE VIDEO SET VID_STATUS = 'IN' WHERE VID_NUM = :NEW.VID_NUM;
ELSIF :NEW.DETAIL_RETURNDATE = '01/01/0001' THEN UPDATE VIDEO SET VID_STATUS = 'LOST' WHERE VID_NUM = :NEW.VID_NUM;
END IF;
END;
最佳答案
好的数据模型是不物理存储冗余信息的模型。如果您可以查看 table.column 中的一个(或多个)值并找出另一个 table.column 中应包含的值,那么您就获得了冗余。在您的情况下,人们可以看到 VIDNUM 61367 的 DETAILRENTAL.DETAIL_DUEDATE 不为空,并且“知道”VIDEO.STATUS 字段应该为 OUT。
最容易通过以下方式修复:
1)创建一个VIDEO_BASE表,其中包含除VID_STATUS之外的所有VIDEO列:
CREATE TABLE VIDEO_BASE AS
SELECT {list all columns except STATUS}
FROM VIDEO;
2) 删除原始 VIDEO 表并创建一个 View VIDEO,该 View 显示 VIDEO_BASE 的所有列,并将 STATUS 公开为派生字段:
CREATE OR REPLACE VIEW VIDEO
AS
SELECT V.*,
CASE WHEN
(
SELECT COUNT(*)
FROM
(
SELECT 'X'
FROM DETAILRENTAL D
WHERE D.VID_NUM = V.VID_NUM
AND DETAIL_RETURNDATE IS NOT NULL
AND ROWNUM <= 1
)
) > 0
THEN 'OUT'
ELSE NULL
END VID_STATUS
FROM VIDEO_BASE V;
一般来说,如果您觉得需要一个触发器来保持两个不同的表同步,那么您就遇到了数据模型问题。根据我 15 年以上的 Oracle 经验,修复有问题的触发器的唯一最佳方法是修复数据模型 - 了解所有触发器正常工作的最可靠方法是当数据库中的触发器数量为 0 时。
关于oracle - 表正在发生变化,触发器/函数可能看不到它 ORA-06512,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33850539/