2012-04-17 46 views
1

我想创建一个触发器,当其中一个属性变为负数时将删除一行。到目前为止,我有这个,但它似乎并不是有效的SQL:创建触发器,在属性变为负数时删除行[oracle sql]?

CREATE OR REPLACE TRIGGER ZERO_COPIES_TRIGGER 
after 
update of counter_attribute 
on my_table 
referencing new as new 
for each row when(new.copies < 0) 
begin 
    delete from my_table where my_table.id = :new.id; 
end; 

回答

5

这是行不通的。您无法在由行级触发器操作的表上执行DML。你会得到一个“变异表”的错误。

为了得到你想要的结果,你最好的办法是有一个标志或指标栏来标识记录是被删除。然后,有一个单独的工作或进程或任何实际执行删除。

+1

如果使用语句级触发器而不是行级触发器,则可以在触发器表上执行DML。 – 2012-04-17 17:46:10

+0

当然可以。我已经更新了我的答案。感谢您指出错误。 – 2012-04-17 20:38:44

3

为了完整起见:另一种选择是有一个说法触发器,它扫描表,然后进行删除,如:

CREATE OR REPLACE TRIGGER ZERO_COPIES_TRIGGER 
     AFTER UPDATE OF COUNTER_ATTRIBUTE ON MY_TABLE 
BEGIN 
    FOR aROW IN (SELECT ID 
       FROM MY_TABLE 
       WHERE COPIES < 0) 
    LOOP 
    DELETE FROM MY_TABLE 
     WHERE ID = aROW.ID; 
    END LOOP; 
END ZERO_COPIES_TRIGGER; 

或者,如果你真的希望有一些乐趣,你可以使用一个混合触发器来处理删除,而不需要一个表扫描,同时还避免了可怕的“变异表”的错误,如:

CREATE OR REPLACE TRIGGER COMPOUND_ZERO_COPIES_TRIGGER 
    FOR UPDATE OF COUNTER_ATTRIBUTE ON MY_TABLE 
COMPOUND TRIGGER 
    TYPE NUMBER_TABLE IS TABLE OF NUMBER; 
    tblDELETE_IDS NUMBER_TABLE; 

    BEFORE STATEMENT IS 
    BEGIN 
    tblDELETE_IDS := NUMBER_TABLE(); 
    END BEFORE STATEMENT; 

    AFTER EACH ROW IS 
    BEGIN 
    IF :NEW.COPIES < 0 THEN 
     tblDELETE_IDS.EXTEND; 
     tblDELETE_IDS(tblDELETE_IDS.LAST) := :NEW.ID; 
    END IF; 
    END AFTER EACH ROW; 

    AFTER STATEMENT IS 
    BEGIN 
    IF tblDELETE_IDS.COUNT > 0 THEN 
     FOR I IN tblDELETE_IDS.FIRST..tblDELETE_IDS.LAST LOOP 
     DELETE FROM MY_TABLE 
      WHERE ID = tblDELETE_IDS(I); 
     END LOOP; 
    END IF; 
    END AFTER STATEMENT; 
END COMPOUND_ZERO_COPIES_TRIGGER; 

分享和享受。