VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
トリガーの作成
BEFORE と AFTER
BEFORE INSERT トリガーはデフォルト値を設定したり、不正なデータを拒否したりできます。AFTER INSERT トリガーは、挿入が成功した後に監査レコードを書き込めます。
NEW と OLD の参照
BEFORE トリガーで NEW の値を変更すると、書き込まれる内容が変わります。
イベントごとの複数トリガー
MySQL は、同じテーブルとイベントに対する複数のトリガーをサポートします。FOLLOWS と PRECEDES キーワードが実行順序を制御します。
FOLLOWS/PRECEDES がない場合、MySQL は作成時刻に基づいて実行順序を割り当てます。
トリガーでのエラーの送出
操作を中止して呼び出し元にエラーを返すには、SIGNAL を使います。
BEFORE トリガーがエラーをシグナルすると、挿入/更新/削除は中止され、何も書き込まれません。
トリガーの制限
MySQL のトリガーには、知っておくべきいくつかの制限があります。- トリガーは、結果セットを返すストアドプロシージャを呼び出せません
- トリガーは
COMMIT、ROLLBACK、SAVEPOINTを直接使えません(周囲のトランザクションに参加します) - トリガーは、自分が定義されているテーブルを参照できません(ほとんどのコンテキストで、同じテーブルへの直接クエリによる再帰的なトリガー呼び出しはできません)
AFTERトリガーはNEWの値を変更できません — 行はすでに書き込まれています- MySQL はステートメントレベルのトリガーをサポートしません(すべてのトリガーは
FOR EACH ROWです)
トリガーを使うべき場面
トリガーは次の用途に適しています。- 監査ログ — アプリケーションに関係なく、誰が何をいつ変更したかを記録する
- CHECK 制約では表現できない複雑な制約の強制
- 派生データの同期(非正規化された集計列、監査タイムスタンプ)
- ロジックが複雑で、デバッグに隠れた副作用の追跡が必要になる場合
- パフォーマンスが重要な場合 — すべてのトリガーは、影響を受けるすべてのステートメントで行ごとに起動します
- トリガーがデータを変更し、その存在を知らないアプリケーション開発者を驚かせる場合
よくある質問
LOAD DATA INFILE の実行中にトリガーは起動しますか?
はい。INSERT トリガーは、LOAD DATA INFILE でロードされる各行に対して起動します。トリガーが大きな作業を行う場合、LOAD DATA による一括ロードは、まずステージングテーブルにロードしてから INSERT…SELECT でコピーするよりもはるかに遅くなります(INSERT…SELECT もトリガーを起動しますが、SET @disable_trigger = TRUE とトリガー内の条件チェックで一時的に無効化できます)。
トリガーからストアドプロシージャを呼び出せますか?
はい。ただし 1 つ例外があります。呼び出されるプロシージャは結果セット(INTO のない SELECT)を返せません。返すと、MySQL はエラーを返します。トリガーから呼び出されるプロシージャは、OUT パラメータと SELECT...INTO を使えます。
REPLACE INTO でトリガーは起動しますか?
REPLACE は、競合があるときに DELETE + INSERT として実行されます。競合時には、対象テーブルで 4 つすべてが次の順序で起動します。BEFORE INSERT(重複キーのチェック)、次に競合する行に対する BEFORE DELETE と AFTER DELETE、最後に AFTER INSERT です。この削除は本物の行削除なので、参照元テーブルの ON DELETE CASCADE ルールも起動します。
トラブルシューティング
関連項目
- MySQL のストアドプロシージャ — トリガーが呼び出せるロジック
- トリガーからの Webhook の送信 — トリガー本体からの HTTP 呼び出し
- MySQL の CHECK 制約 — トリガーがよく実装する検証ルールのより単純な代替手段