我想创建一个触发器,当其中一个属性变为负数时将删除该行。到目前为止,我有这个,但它似乎不是有效的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;
答案 0 :(得分:5)
这不起作用。您无法在由行级触发器操作的表上执行DML。您将收到“变异表”错误。
要获得您想要的结果,最好的办法是设置一个标记或指示符列,以标识记录要删除。然后,有一个单独的工作或过程或任何实际执行删除。
答案 1 :(得分: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;
或者,如果真的希望获得一些乐趣,您可以使用复合触发器来处理删除操作,而无需进行表扫描,同时仍然避免可怕的“MUTATING TABLE”错误,如在:
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;
分享并享受。