我是PL/SQL
中的新手,我试图通过触发器进行相当复杂的数据完整性检查。
我已经理解了如何在同一个桌面上使用的触发器内调用表(通过临时外部表)时如何避免问题,但现在我面临一个非常令人兴奋的问题:我认为":NEW"
引用了我的表AFTER
中的值更新,但事情看起来并不那么简单......这是更新或插入的新值SET
...如果没有指定任何内容,它看起来是NULL
,即使更新后相应的字段值为NOT NULL
...这让我发疯了。
插入或更新多个变量时设置了我的触发器:
CREATE OR REPLACE TRIGGER TRG_INS_UP_INSTRUMENT_EVENT
AFTER INSERT OR UPDATE OF EVENT_ID, DATE_BEGIN,DATE_END,INSTR_ID,TYPE_EVENT_ID ON AIS_INSTRUMENT_EVENT
但是现在......如果已经有一个非空字段的行,我会做
UPDATE AIS_INSTRUMENT_EVENT SET INSTR_ID='642' WHERE EVENT_ID='6479'
我实际上得到的":NEW.DATE_BEGIN"
是NULL
...事件被认为,旧的或更新的值都是NULL(因为我没有更新它)。
我如何区分 - 在我的触发器中 - DATE_BEGIN
更新的情况和SET
自愿到NULL
的情况,其中没有指定任何内容(此字段必须因此保持不变但不一定是NULL ...)。我需要多种可能的组合来逐一检查...
提前感谢您的帮助!
答案 0 :(得分:1)
你说的不是真的。 :new包含完整行,无论该列是否在UPDATE语句中引用:
CREATE TABLE test (test INTEGER, last_changed DATE);
CREATE OR REPLACE TRIGGER TRG_INS_UP_TEST
AFTER INSERT OR UPDATE OF test, last_changed ON test
FOR EACH ROW
BEGIN
dbms_output.put_line('LAST CHANGED IS ' || :new.last_changed);
END;
INSERT INTO test (test, last_changed) VALUES (1, SYSDATE);
COMMIT;
UPDATE test SET test = test + 1;
DBMS输出:
LAST CHANGED IS 01.09.17
为了达到你想要的效果,机制的工作方式略有不同。您必须查看两个不同的用例:
1。)除非提到某个列,否则您希望触发器不会触发。此用例是通过触发器声明中的引用(INSERT OR UDATE OF“column_name”)。如果INSERT / UPDATE语句仅影响未提及的列,则触发器将不会触发。
2.。)除非修改某一行,否则不要触发触发器。因此,只有当fire值实际发生了变化时,才需要触发器。这是通过WHEN限制触发器来完成的。它通常与DECODE一起使用,如下所示:
CREATE OR REPLACE TRIGGER TRG_INS_UP_TEST
AFTER INSERT OR UPDATE OF test, last_changed ON test
FOR EACH ROW
WHEN (DECODE(new.test,old.test,0,1)=1 OR DECODE(new. last_changed,old. last_changed,0,1)=1)
BEGIN
...
END;
所以回答你原来的问题:如果你想要触发器,只有在DATE_BEGIN列设置为NULL的情况下才会触发,你必须使用两种方法声明你的触发器
CREATE OR REPLACE TRIGGER TRG_INS_UP_INSTRUMENT_EVENT
AFTER INSERT OR UPDATE OF DATE_BEGIN ON AIS_INSTRUMENT_EVENT
FOR EACH ROW
WHEN (DECODE(new.DATE_BEGIN,old. DATE_BEGIN,0,1)=1 AND new.DATE_BEGIN IS NULL)
对某些列的限制(“INSERT OR DATE_BATE更新”)并不是绝对必要的,但这是一种很好的做法,因为它可以提高性能,因为它根本不会触发触发器。
答案 1 :(得分:0)
抱歉,我想我快速得出结论......这个错误是我的。我已经测试了玩具"表,实际上,即使没有UPDATE设置,NEW也不为null。我在此期间发现了这个错误。这对我来说太新了; - )。
抱歉令人不安。