1

属性の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 に答える