| Oracle Database 2日で開発者ガイド 11g リリース1(11.1) E05694-03 |
|
この章では、データベースの表、ビューまたはイベントと関連付けられたストアド・プロシージャのコードであるデータベース・トリガーについて説明します。
この章の内容は次のとおりです。
トリガーはデータベースで指定したイベントが発生した際に、自動的に起動されるストアド・プロシージャのコードです。トリガーは表、ビューまたはイベントと関連付けられます。プロシージャおよびファンクションとは異なり、トリガーは直接的に起動できません。そのかわり、Oracle Databaseはユーザーまたはアプリケーションに関係なくトリガーされたイベントが発生したときに、トリガーを暗示的に起動します。トリガーを起動したイベントが失敗した場合、オペレーションが正常に処理されないエラーを発生させないかぎり、トリガーが活動していることに気づかないでしょう。
トリガーを正しく使用することで、より効率的なデータベースを使用でき、より堅固でセキュアなアプリケーションを構築およびデプロイできます。これらの利点は、トリガーが次の機能を提供することで実現可能になります。
データベースに固有で、そのためにすべてのクライアント・アプリケーションに共通の低いレベルのビジネス・ルールを強化するトリガーを使用できます。たとえば、hrスキーマのemployees表にアクセスするいくつかのクライアント・アプリケーションがあると思います。この表に対するトリガーが、表に追加されるすべてのデータが正しい形式であることを確認する場合、このビジネス・ロジックはすべてのクライアント・アプリケーションで再生産およびメンテナンスを行う必要がありません。これは、トリガーがクライアント・アプリケーションによって回避できず、トリガーに格納されたビジネス・ロジックが自動的に使用されるためです。
各トリガーには次の一般的な書式が含まれます。
TRIGGER trigger_name triggering_statement [trigger_restriction] BEGIN triggered_action; END;
トリガーには4つの主要な部分があります。
INSERT、UPDATEおよびDELETE)、スキーマ・オブジェクトのDDL文(CREATE、ALTERおよびDROP)、システム・エラー、データベースの起動および終了、また他のシステム・アクションが含まれます。トリガーを実行する文はトリガーの制限の影響を受けます。
TRUEと評価する場合のみ、データベースはトリガーされたアクションを実行するという意味です。
TRUEと評価する際に両方に実行される一連の手順です。 Oracle Databaseのトリガーには5つの異なるタイプがあります。
DELETE、INSERTまたはUPDATEなどのDML文と関連付けられています。 文トリガーは各DML文に対して一度起動します。たとえば、UPDATE文トリガーは、表の影響を受ける行数に関係なく一度のみ実行します。
Oracle Databaseリリース11g R1から、特定のDML文と関連付けられたいくつかの異なるトリガーを所持できます。CREATE TRIGGER文のFOLLOWSおよびPRECEDES句を使用して、実行される順序を指定できます。
INSERT、UPDATEまたはDELETE文に影響を受ける各行に対して起動します。 行トリガーは文トリガーとして同一の方法で機能しますが、2つの追加の指定を使用します。行トリガーはトリガー中の文でFOR EACH ROW句を使用します。また、行トリガーによって、行の値を参照し、トリガーの本体でイベントをトリガーに設定できます。これは特に、デフォルト値の挿入および無効な値の上書きに便利です。
INSTEAD OFトリガーを実行します。INSERT文がビューで使用されている場合、INSTEAD OFトリガーを使用して、実表または他の表へのデータの挿入、データの挿入が不要な挿入要求のロギングなどの実際に発生する処理の密な制御を実行できます。 また、Oracle Databaseはビューに対して発行された挿入の処理ができない場合があります。生成された列の場合、値を正確に決定するトリガーを作成できます。たとえば、ビューが列定義last_name || ', ' || first_nameを使用していた場合、last_name列中でカンマ文字の前の文字およびfirst_name列中でカンマ文字の後の文字を更新する、INSTEAD OFトリガーが記述されている可能性があります。
CREATE、ALTER、DROPなどのDDL文、ユーザーLOGONおよびLOGOFF、特定のDMLアクション(分析および統計、監査、付与および権限の取消しなど)で使用できます。ユーザーがデータベースへ接続した時に起動するLOGONトリガーは、ユーザーに対して環境を設定し、セキュアなアプリケーション・ロールと関連付けられたファンクションを実行するために一般的に使用されます。
参照:
CREATE TRIGGER文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
トリガーはトリガー中の文でBEFOREまたはAFTER句を使用できます。BEFOREおよびAFTERで、トリガーを起動するイベントの前または後のどちらにトリガーを実行するかを指定します。文および行トリガーでは、BEFOREトリガーはセキュリティを強化でき、データベースへの変更を行う前にビジネス・ルールを有効にします。一方、AFTERトリガーはロギング・アクションに非常に役立ちます。
INSTEAD OFトリガーはBEFOREまたはAFTERオプションを使用しません。デフォルトでは、これらのオプションはAFTERの行レベルのトリガーとして同一のセマンティクスを使用します。
システムおよびユーザー・イベント・トリガーでは、明らかな例外を除いて、BEFORE句およびAFTER句を使用できます。これらの例外は、AFTERがSTARTUP、SUSPENDおよびLOGONに有効な場合、およびBEFOREがSHUTDOWNおよびLOGOFFに有効な場合のみです。
アプリケーションのトリガーを計画する際に次のガイドラインおよび制限を検討する必要があります。
BEFORE句およびAFTER句を正確に使用していることを確認します。BEFORE EACH ROWトリガーは:NEW値を変更できます。
COMMIT、ROLLBACKまたはSAVEPOINTを使用できません。これは、DDL文に暗黙的COMMITが含まれ、DDL文もトリガーでは使用できないためです。システム・トリガーのCREATE、ALTER、DROP TABLE、ALTER...COMPILEは、除きます。
この項では、様々なタイプのトリガーの作成および使用方法を示します。
この項には、次のトピックが含まれます。
文トリガーは、INSERT、UPDATEまたはDELETEなどの特定の文に関連しています。これらは特定の表で実行されるので、これらの操作のロギングに対して文トリガーを使用できます。
例5-1は、ログ表の作成方法を示しています。
evaluations_log表にはevaluations表で各INSERT、UPDATEまたはDELETEを持つエントリが格納されます。
CREATE TABLE evaluations_log (log_date DATE , action VARCHAR2(50));
例5-2では、evaluations表が変更されるたびにevaluations_logに書き込むトリガーを作成します。
トリガーeval_change_triggerは、evaluations表に対するすべての変更を追跡し、これらの変更が行われた後に新しい行を追加することによってevaluations_log表で変更を追跡します。この例では、使用可能な3つの文からトリガーを起動する文を決定するために、トリガーの本体で条件述語INSERTING、UPDATINGまたはDELETINGが使用されていることに注意してください。
CREATE OR REPLACE TRIGGER eval_modification_trigger AFTER INSERT OR UPDATE OR DELETE ON evaluations DECLARE log_action evaluations_log.action%TYPE; BEGIN IF INSERTING THEN log_action := 'Insert'; ELSIF UPDATING THEN log_action := 'Update'; ELSIF DELETING THEN log_action := 'Delete'; ELSE DBMS_OUTPUT.PUT_LINE('This code is not reachable.'); END IF; INSERT INTO evaluations_log (log_date, action) VALUES (SYSDATE, log_action); END;
行トリガーは影響を受けるそれぞれの行に対して実行されます。
「順序の使用」で、evaluations_seq順序をevaluations表に対する主キー番号ジェネレータとして作成しました。Oracle Databaseでは、CREATE TABLE文の一部として、主キーは自動的に作成されません。かわりに、INSERT文を使用して主キーに対する一意の番号を生成するトリガーを設計する必要があります。
次のタスクでは、SQL Developer Connectionナビゲーション階層を使用して、トリガーnew_evaluationを作成します。このトリガーは、同一の従業員の行が同一の期間に存在するかどうかに基づいて、新しい表をevaluations表に追加する必要があるかどうかをチェックします。
「Trigger」ペインで、「Trigger Type」をTABLEに、次に「Table Owner」をHRに、そして「Table Name」をevaluationsに設定し、「Before」、「Insert」および「Row Level」の順で選択します。
「OK」をクリックします。
new_evaluationペインを次のコードを使用してオープンします。ペインのタイルがイタリック・フォントになっていることに注意してください。トリガーがデータベースに保存されていないことを示しています。
CREATE OR REPLACE TRIGGER new_evaluation BEFORE INSERT ON evaluations FOR EACH ROW BEGIN NULL; END;
Oracle Databaseにより、トリガーは保存前に自動的にコンパイルされます。
INSTEAD OFトリガーでは、表示の基礎となる表に対する変更を実装できます。このようなトリガーは「ビューの作成」で作成した emp_locationsビューで使用されます。emp_locationsの定義を確認します。
CREATE VIEW emp_locations AS SELECT e.employee_id, e.last_name || ', ' || e.first_name name, d.department_name department, l.city city, c.country_name country FROM employees e, departments d, locations l, countries c WHERE e.department_id = d.department_id AND d.location_id = l.location_id AND l.country_id = c.country_id ORDER BY last_name;
例5-4では、INSTEAD OFトリガーupdate_name_view_triggerを実装して、従業員の名前を更新します。
CREATE OR REPLACE TRIGGER update_name_view_trigger INSTEAD OF UPDATE ON emp_locations BEGIN -- allow only the following update(s) UPDATE employees SET first_name = substr( :NEW.name, instr( :new.name, ',' )+2), last_name = substr( :NEW.name, 1, instr( :new.name, ',')-1) WHERE employee_id = :OLD.employee_id; END;
LOGONおよびLOGOFFトリガーは、ログ表へ書き込むことで、データベースの使用者を監視します。
例5-5では、LOGONおよびLOGOFFイベントの追跡を続行するためにhr_users_log表を作成します。その後、これらのイベントをログ表に書き込むために、トリガーnote_hr_logon_trigger(例5-6)およびnote_hr_logoff_trigger(例5-7)を作成します。
この表はhrスキーマでのすべてのログオンおよびログイン・イベントのログです。
CREATE TABLE hr_users_log (user_name VARCHAR2(30), activity VARCHAR2(20), event_date DATE);例5-6 LOGONトリガーの作成
hrスキーマに接続すると、このトリガーによりLOGONイベント・レコードがhr_users_log表に挿入されます。これはAFTERトリガーであることに注意してください。
CREATE OR REPLACE TRIGGER note_hr_logon_trigger AFTER LOGON ON HR.SCHEMA BEGIN INSERT INTO hr_users_log VALUES (USER, 'LOGON', SYSDATE); END;例5-7 LOGOFFトリガーの作成
hrスキーマへの接続が切断されると、このトリガーによりLOGOFFイベント・レポートがhr_users_log表に挿入されます。これはBEFOREトリガーであることに注意してください。
CREATE OR REPLACE TRIGGER note_hr_logoff_trigger BEFORE LOGOFF ON HR.SCHEMA BEGIN INSERT INTO hr_users_log VALUES (USER, 'LOGOFF', SYSDATE); END;
new_evaluation_triggerには空の本体があります。
例5-8は、evaluations_seq順序の次の使用可能な値をevaluation_idに割り当てるトリガーの変更方法を示しています。
次のコードを使用して、new_evaluation_triggerを置換します。新規コードは太字フォントです。
CREATE OR REPLACE TRIGGER new_evaluation_trigger BEFORE INSERT ON evaluations FOR EACH ROW BEGIN :NEW.evaluation_id := evaluations_seq.NEXTVAL; END;
トリガーが参照するオブジェクトが使用不可能である場合またはトリガーが原因の遅延なしに大規模なデータのアップロードを実行する必要がある場合(リカバリ操作など)、トリガーを一時的に無効にする必要があります。
トリガーを無効にするには、ALTER TRIGGER ... DISABLE文を使用する必要があります。トリガーを再度有効にするには、ALTER TRIGGER ... ENABLE文を使用します。
例5-9は、トリガーを一時的に無効にする方法を示しています。
ALTER TRIGGER eval_change_trigger DISABLE;
例5-10は、トリガーを再度有効にする方法を示しています。
ALTER TRIGGER eval_change_trigger ENABLE;
特定の表のすべてのトリガーを無効にする必要がある場合は、ALTER TABLE ... DISABLE ALL TRIGGERS文を使用する必要があります。表のすべてのトリガーを再度有効にするには、ALTER TABLE ... ENABLE ALL TRIGGERS文を使用します。
例5-11は、特定の表で定義されたすべてのトリガーを一時的に無効にする方法を示しています。
ALTER TABLE evaluations DISABLE ALL TRIGGERS;
例5-12は、特定の表で定義されたすべてのトリガーを再度有効にする方法を示しています。
ALTER TABLE evaluations ENABLE ALL TRIGGERS;
CREATE TRIGGER文が実行されると、トリガーは完全にコンパイルされます。トリガーのコンパイルでエラーが生じた場合、DML文は失敗します。関連したコンパイル・エラーを表示するには、USER_ERRORSビューを使用します。
例5-13に、データベースに存在するトリガー・エラーを判断する方法を示します。
SELECT * FROM USER_ERRORS WHERE TYPE = 'TRIGGER';
トリガーがコンパイルされると、基礎となるデータベース・オブジェクトに依存性を作成し、トリガーとオブジェクトが一致しないようにこれらのオブジェクトが削除または変更された場合はトリガーが無効になります。無効なトリガーは次の起動時に再コンパイルされます。
例5-14は、データベース内の他のオブジェクトにあるトリガー依存性を確認する方法を示しています。
SELECT * FROM ALL_DEPENDENCIES WHERE TYPE = 'TRIGGER';
手動でトリガーを再コンパイルするには、例5-15に示すようにALTER TRIGGER ... COMPILE文を使用する必要があります。
ALTER TRIGGER update_name_view_trigger COMPILE;
トリガーを削除する必要がある場合は、例5-16に示すようにDROP TRIGGER文を使用します。
DROP TRIGGER eval_change_trigger;
トリガーの削除後、アプリケーションに必要のない依存オブジェクトを削除できます。
|
![]() Copyright © 2005, 2008, Oracle Corporation. All Rights Reserved. |
|