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