sql >> データベース >  >> RDS >> Oracle

挿入または削除後のOracleトリガー

    あなたが遭遇したのは、古典的な「ミューティングテーブル」の例外です。 ROWトリガーでは、Oracleでは、トリガーが定義されているテーブルに対してクエリを実行することはできません。したがって、これはSELECTです。 DELETINGのTABLE1に対して この問題を引き起こしているトリガーの一部。

    これを回避するには、いくつかの方法があります。おそらく、この状況で最適なのは、次のような複合トリガーを使用することです。

    CREATE OR REPLACE TRIGGER TABLE1_NUM_TRG
      FOR INSERT OR DELETE ON TABLE1
    COMPOUND TRIGGER
      TYPE NUMBER_TABLE IS TABLE OF NUMBER;
      tblTABLE2_IDS  NUMBER_TABLE;
    
      BEFORE STATEMENT IS
      BEGIN
        tblTABLE2_IDS := NUMBER_TABLE();
      END BEFORE STATEMENT;
    
      AFTER EACH ROW IS
      BEGIN
        IF INSERTING THEN
          UPDATE TABLE2 t2
            SET    t2.TABLE2NUM = :new.NUM
            WHERE  t2.ID = :new.TABLE2_ID;
        ELSIF DELETING THEN
          tblTABLE2_IDS.EXTEND;
          tblTABLE2_IDS(tblTABLE2_IDS.LAST) := :new.TABLE2_ID;
        END IF;
      END AFTER EACH ROW;
    
      AFTER STATEMENT IS
      BEGIN
        IF tblTABLE2_IDS.COUNT > 0 THEN
          FOR i IN tblTABLE2_IDS.FIRST..tblTABLE2_IDS.LAST LOOP
            UPDATE TABLE2 t2
              SET t2.TABLE2NUM = (SELECT NUM
                                    FROM (SELECT t1.NUM
                                            FROM TABLE1 t1
                                            WHERE t1.TABLE2_ID = tblTABLE2_IDS(i) 
                                            ORDER BY modification_date DESC)
                                    WHERE ROWNUM = 1)
              WHERE t2.ID = tblTABLE2_IDS(i);
          END LOOP;
        END IF;
      END AFTER STATEMENT;
    END TABLE1_NUM_TRG;
    

    複合トリガーにより、各タイミングポイント(BEFORE STATEMENTBEFORE ROWAFTER ROW 、およびAFTER STATEMENT )処理されます。タイミングポイントは常に指定された順序で呼び出されることに注意してください。適切なSQLステートメント(つまり、INSERT INTO TABLE1 またはDELETE FROM TABLE1 )が実行され、このトリガーが起動されます。呼び出される最初のタイミングポイントはBEFORE STATEMENTになります。 、およびBEFORE STATEMENTのコード ハンドラは、多数の数値を保持するためにPL/SQL表を割り当てます。この場合、PL / SQL表に格納される数値は、TABLE1のTABLE2_ID値になります。 (たとえば、テーブルはさまざまな数の値を保持できるため、配列の代わりにPL / SQLテーブルが使用されますが、配列を使用する場合は、格納する必要のある数値を事前に知っておく必要があります。特定のステートメントの影響を受ける行数を事前に知ることはできないため、PL /SQL表を使用します。

    AFTER EACH ROWの場合 タイミングポイントに到達し、処理中のステートメントがINSERTであることがわかりました。トリガーは先に進み、問題が発生しないため、TABLE2に対して必要なUPDATEを実行します。ただし、DELETEが実行されている場合、トリガーはTABLE1.TABLE2_IDを前に割り当てられたPL/SQL表に保存します。 AFTER STATEMENT 最終的にタイミングポイントに到達し、前に割り当てられたPL / SQL表が繰り返され、TABLE2_IDが見つかるたびに、適切な更新が実行されます。

    ドキュメントはこちら。



    1. SQL FLOAT:奇妙な数学エラーを回避するのに役立つ3つのポイント

    2. PythonがSSHトンネリングを介してMySQLに接続できるようにする

    3. 読み取り/書き込みレイテンシの監視

    4. 初心者向けSQLAVG()