1

我想创建一个触发器,当它的一个属性变为负数时将删除一行。到目前为止,我有这个,但它似乎不是有效的 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;
4

2 回答 2

5

这是行不通的。您不能对由行级触发器操作的表执行 DML。您将收到“变异表”错误。

要获得您想要的结果,最好的办法是有一个标志或指示列来标识要删除的记录。然后,有一个单独的作业或进程或任何实际执行删除的东西。

于 2012-04-17T03:59:04.567 回答
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;

分享和享受。

于 2012-04-17T17:03:19.030 回答