複合トリガーを試す:
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 statement
、 BEFORE-for each row
、 AFTER 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
.これは単一の更新ステートメントですが、一度に多くの行を変更します。トリガーの実行順序は次のとおりです。
UPDATE treballa SET salary = salary + 10
Departments
です。 変数が初期化されましたBEFORE EACH ROW
section は、更新された行ごとに個別に実行されます - 更新される行の数だけ実行されます。この場所では、変更された行からすべての部門を収集します。AFTER STATEMENT
セクションが実行されます。この時点で、テーブルはすでに更新されています。すべての行には、新しく更新された給与がすでに含まれています。 Departments
に保存されている部門をループします それぞれについて、給与の合計が 1000 以下かどうかを確認します。これらの部門のいずれかでこの合計が 1000 を超える場合、エラーがスローされ、更新全体が中止され、ロールバックされます。それ以外の場合は、トリガーが終了し、更新が完了します (ただし、これらの変更をコミットする必要があります)。
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 のセットを取得します。