本文へスキップ
BecomeCoder

SQL テーブル設計 (DDL)コース · 第5章 テーブルの先へ · レッスン17

トリガー ― 変更に反応して自動で動く

ブラウザで完結

導入

「注文明細が追加されたら、自動でログを残したい」「行が更新されたら、更新日時を自動で記録したい」――こういう「何かが起きたら、ついでにこれもやる」を、アプリ側で毎回書くのは大変ですし、書き忘れも起きます。データベース自身に「変更が起きたら自動でこれを実行して」と仕込めるのが トリガー(Trigger) です。

説明

トリガーは「きっかけ(イベント)」と「実行する処理」の組です。きっかけは INSERT / UPDATE / DELETE のいずれかで、そのテーブルに変更が起きた瞬間に、仕込んだ SQL が自動で走ります。

sequenceDiagram
  participant A as あなたのSQL
  participant O as order_items テーブル
  participant T as トリガー
  participant L as item_log テーブル
  A->>O: INSERT INTO order_items ...
  O-->>T: 行が追加された!(イベント発火)
  T->>L: 自動で INSERT INTO item_log ...
  Note over A,L: あなたは1文しか書いていないのに、ログも自動で残る

例として、「order_items に新しい明細が入ったら、item_log に記録を残す」トリガーを作ります。トリガーの中では、追加された行を NEW という特別な名前で参照できます(NEW.product_id で新しい行の product_id)。

-- 1. ログをためるテーブルを用意
CREATE TABLE item_log (
  id       INTEGER PRIMARY KEY,
  item_id  INTEGER,
  note     TEXT
);

-- 2. 「order_items に INSERT されたら自動で item_log に書く」トリガー
CREATE TRIGGER log_new_item
AFTER INSERT ON order_items
BEGIN
  INSERT INTO item_log (item_id, note)
  VALUES (NEW.id, '明細 ' || NEW.product_id || ' が ' || NEW.quantity || '個 追加');
END;

-- 3. 明細を1件入れてみる(あなたが書くのはこの1文だけ)
INSERT INTO order_items (id, order_id, product_id, quantity)
  VALUES (12, 7, 5, 2);

-- 4. ログを見ると…自動で1行増えている
SELECT * FROM item_log;

AFTER INSERT ON order_items が「order_items に INSERT したに発火」という意味です。AFTER のほかに BEFORE(変更の前)もあり、イベントも INSERT / UPDATE / DELETE から選べます。UPDATE のトリガーでは、変更前の行を OLD、変更後を NEW で参照できます。

便利な反面、注意も要ります。 トリガーは「見えないところで勝手に動く」ため、増やしすぎると「なぜこの行が入ったのか」を追いづらくなります。実務では、監査ログ・自動集計・整合性チェックなど、用途を絞って使うのが定番です。作ったトリガーは DROP TRIGGER トリガー名; で消せます。今あるトリガーは、SQLite なら初期表示のクエリで一覧できます。

やってみよう

まず初期表示のクエリを実行すると、トリガーはまだ何もないので空です。次に、上の「1〜4」のコードをまるごとコピーして貼り付け、実行してください。あなたは order_items に1件 INSERT しただけなのに、SELECT * FROM item_log; にログが自動で増えていることを確認しましょう。

演習

order_items行が削除されたら、その明細IDを item_log に「削除」と記録するトリガー log_deleted_item を作ってください(item_log は上で作成済みとします。削除された行は OLD で参照します)。

ヒント1を見る

CREATE TRIGGER 名前 AFTER DELETE ON order_items BEGIN ... END; の形。中で OLD.id を使います。

ヒント2を見る

CREATE TRIGGER log_deleted_item AFTER DELETE ON order_items BEGIN INSERT INTO item_log (item_id, note) VALUES (OLD.id, '削除'); END;

実際に動かしてみよう

下のエディタにクエリを書いて「実行」を押すと、ブラウザ内のSQLiteで結果が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう。

SQL — ブラウザ内で実行(SQLite)

ブラウザ内でSQLを動かす環境(SQLite)を読み込みます(初回のみ一瞬)。
スクロールして表示された時点でも自動で読み込まれます。