【SQL実践|実務向け】SQLiteトリガー活用術:OLDとNEWで実現するデータ整合性の自動制御

1. 導入:なぜトリガーで「値の参照」が必要なのか

データベース運用において、アプリケーションコード側で整合性を保つロジックを書くと、複雑化しやすく保守性が低下します。例えば「ユーザー名が変更されたら、関連する全ての履歴テーブルも連動して更新する」といった処理を漏れなく実装するのは困難です。SQLiteのトリガー機能を利用し、更新前(OLD)と更新後(NEW)の値を直接参照することで、DB側で堅牢なデータ整合性を自動的に担保できるようになります。

2. 基礎知識:OLDとNEWの役割

SQLiteのトリガー内で使用できる「OLD」と「NEW」は、行レベルの変更前後の値を保持する特別なプレフィックスです。

OLD.カラム名: 削除(DELETE)や更新(UPDATE)の対象となった「元の値」を参照します。
NEW.カラム名: 追加(INSERT)や更新(UPDATE)によって設定される「新しい値」を参照します。

これらを適切に使い分けることで、データの追跡や連鎖的な更新処理が実現できます。

3. 実装/解決策:トリガー定義の基本

トリガーを作成する際は、`CREATE TRIGGER`文の中でこれらのエイリアスをSQL文に組み込みます。重要なのは、更新(UPDATE)時は「OLDで条件を絞り、NEWで値を書き換える」という論理構成にすることです。

4. サンプルプログラム:商品名変更を履歴へ連動させる

以下は、マスタテーブル(product)のデータが変更された際、履歴テーブル(history)のデータを自動追従させる実用的な例です。

/ 商品名管理テーブルの作成 /
CREATE TABLE product(id INTEGER, name TEXT);

/ 購入履歴テーブルの作成 /
CREATE TABLE history(user TEXT, name TEXT, sales INTEGER);

/

  • UPDATEトリガーの作成
  • productテーブルのnameカラムが更新されたら、
  • historyテーブルのnameも新しい値に同期させる

/
CREATE TRIGGER update_product_name
UPDATE OF name ON product
BEGIN
/ OLD.nameで古い名称を特定し、NEW.nameで新しい名称に更新する /
UPDATE history
SET name = NEW.name
WHERE name = OLD.name;
END;

/ 動作確認用:データの挿入 /
INSERT INTO product VALUES(1, ‘Notebook’);
INSERT INTO history VALUES(‘Tanaka’, ‘Notebook’, 100000);

/ 商品名の更新を実行(トリガーが自動起動) /
UPDATE product SET name = ‘Laptop’ WHERE name = ‘Notebook’;

/ 結果確認:historyテーブルのnameが’Laptop’に更新されているはずです /
SELECT FROM history;

5. 応用・注意点:現場での運用Tips

・再帰的なトリガーに注意:
トリガー内で更新しているテーブル自体に別のトリガーが設定されていると、無限ループを引き起こす可能性があります。SQLiteの設計において、トリガーの連鎖は慎重に計画してください。

・パフォーマンスへの影響:
トリガーはトランザクションの一部として実行されます。大量のレコードを一括更新(バルクUPDATE)する場合、トリガー内の処理が重いと全体の処理時間が大幅に増大します。トリガー内でのクエリには、必ずインデックスが効くカラムを条件(WHERE句)に使用してください。

・デバッグの難しさ:
トリガーは透過的に動くため、予期せぬデータ不整合が起きた際に原因を特定しづらい傾向があります。運用環境では、トリガーの処理ログを記録するか、ドキュメントにトリガーの依存関係を明記しておくことが、DBAとしての必須事項です。

コメント

タイトルとURLをコピーしました