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

更新トリガー PL/SQL Oracle

    複合トリガーを試す:

    CREATE OR REPLACE TRIGGER compound_trigger_name
    FOR  INSERT OR UPDATE OF salary ON treballa
    COMPOUND TRIGGER
    
      TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
      Departments          Departments_t;
    
         BEFORE EACH ROW IS
         BEGIN
            -- collect updated or inserted departments 
            Departments( :new.department ) := :new.department;
         END BEFORE EACH ROW;
    
         AFTER STATEMENT IS
            sum_sal NUMBER;
         BEGIN
          -- for each updated department check the restriction
          FOR dept IN Departments.FIRST .. Departments.LAST
          LOOP
             SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
             IF sum_sal > 1000 THEN
                raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
             END IF;
          END LOOP;
         END AFTER STATEMENT;
    
    END compound_trigger_name;
    /
    

    ========編集 - いくつかの質問と回答 ===========

    Q:変更テーブル エラーが発生するのはなぜですか?
    A:これは次のドキュメントに記載されています。 ">http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

    Q:テーブルの変更エラーを回避するにはどうすればよいですか?
    A:ドキュメントでは複合トリガーの使用を推奨しています。次を参照してください:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

    Q:複合トリガーとは何ですか?それはどのように機能しますか?
    A:これは大きなトピックです。次のドキュメントを参照してください:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

    要するに、これは 4 種類の別々のトリガーを組み合わせることを可能にする特別な種類のトリガーです:BEFORE statementBEFORE-for each rowAFTER for each row および AFTER statament 1つの宣言に。これにより、あるトリガーから別のトリガーにデータを渡す必要があるシナリオの実装が容易になります。詳細については、上記のリンクをご覧ください。

    Q:しかし、実際には "Departments( :new.department ) := :new.department; とは何ですか? ?
    A:この宣言は部門番号を連想配列に格納します。

    この配列は複合トリガーの宣言部分で宣言されます:

      TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
      Departments          Departments_t;
    

    複合トリガーに関連するドキュメントには、次のように記載されています。 ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

    上記は Departments を意味します 変数は、トリガーが起動した直後、処理全体の開始時に 1 回だけ初期化されます。 「発火ステートメントの持続時間」は、トリガーが終了した後にこの変数が破棄されることを意味します。

    このステートメント:Departments( :new.department ) := :new.department; 部門番号を連想配列に格納します。 BEFORE EACH ROW にあります セクションの場合、update/insert ステートメントによって更新 (または挿入) される行ごとに実行されます。

    :new および :old 詳しくは、 を参照してください。 http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
    要するに::new.department department の新しい値を取得します column- 現在更新されている行 (更新された値 - 更新後)、:old.department この列の古い値を返します (更新前)。

    このコレクションは後で AFTER STATEMENT で使用されます。 、トリガーがすべての更新された部門を (FOR-LOOP で) 選択すると、部門ごとに SELECT SUM(salary) ... が起動します 次に、この合計が 1000 未満かどうかをチェックします

    単純な更新を考えてみましょう:UPDATE treballa SET salary = salary + 10 .これは単一の更新ステートメントですが、一度に多くの行を変更します。トリガーの実行順序は次のとおりです。

    <オール>
  1. 更新ステートメントが起動されます:UPDATE treballa SET salary = salary + 10
  2. トリガーの宣言セクションが実行されます。つまり、Departments です。 変数が初期化されました
  3. BEFORE EACH ROW section は、更新された行ごとに個別に実行されます - 更新される行の数だけ実行されます。この場所では、変更された行からすべての部門を収集します。
  4. AFTER STATEMENT セクションが実行されます。この時点で、テーブルはすでに更新されています。すべての行には、新しく更新された給与がすでに含まれています。 Departments に保存されている部門をループします それぞれについて、給与の合計が 1000 以下かどうかを確認します。これらの部門のいずれかでこの合計が 1000 を超える場合、エラーがスローされ、更新全体が中止され、ロールバックされます。それ以外の場合は、トリガーが終了し、更新が完了します (ただし、これらの変更をコミットする必要があります)。
  5. Q:連想配列とは何ですか? また、他のコレクション (VARRAY またはネストされたテーブル) ではなく、この種のコレクションだけが使用されるのはなぜですか?
    A:PL/SQL コレクションは大きなトピックです。次のリンクに従って学習してください:http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

    要するに、連想配列 (またはインデックス付きテーブル) は、Java のマップ (ハッシュマップ、ツリーマップなど) のようなものです。キーと値のペアのセットであり、各キーはユニーク .この配列に同じキーを (異なる値で) 何度も入れることができますが、このキーは 1 回だけ格納されます。これは一意です。
    これを使用して、部署の一意のセットを取得しました。
    更新の例をもう一度考えてみましょう:UPDATE treballa SET salary = salary + 10 - このコマンドは、同じ部門を持つ何百もの行に影響を与えます。同じ部門が 100 回も重複するコレクションは必要ありません。部門の一意のセットが必要で、クエリ SELECT sum()... を実行したいです。 100回ではなく、部門ごとに1回だけです。 sssociative 配列の助けを借りて、これは自動的に行われます - 独自の deparments のセットを取得します。




    1. PHPで変更/改訂スクリプトを追跡しますか?

    2. MySQL安全な更新モードを使用していて、WHEREなしでテーブルを更新しようとしました

    3. mysqlの日付フィールドと日と月のみを比較します

    4. liferayはデータをhsqlからmysqlに移行します