はじめに
本記事では、SQLiteにおける外部キーの概念と設定方法をまとめます。
外部キーを設定することで、テーブル間のデータの整合性を
データベース側で自動的に保つことができます。
実行環境
| 項目 | 内容 |
|---|---|
| DB | SQLite 3.x |
| OS | Windows 11 |
1. 外部キーとは
複数のテーブルを関連付けるための制約です。
例として、part(部品)テーブルとorder(注文)テーブルを考えます。
partテーブル(親)
| id | name |
|---|---|
| 1 | ボルト |
| 2 | ナット |
orderテーブル(子)
| id | part_id | quantity |
|---|---|---|
| 1 | 1 | 100 |
| 2 | 2 | 50 |
order.part_idがpart.idを参照しています。
これが外部キーです。
この設定により
order.part_idがpart.idを参照することで、
「存在しない部品への注文」が登録できなくなります。
外部キーのメリット・デメリット
| 内容 | 捕捉 | |
|---|---|---|
| メリット | データの整合性をDB側で保証できる | 存在しない親データへの参照をDBが自動で弾く |
| メリット | アプリ側のチェック処理を削減できる | 整合性チェックをSQLに任せられるためコードがシンプルになる |
| メリット | CASCADEで関連データを自動管理できる | 親の削除・更新に子を自動追従させられる |
| メリット | CASCADEで一括変更が可能 | 親テーブルの値を変更するだけで関連する子テーブル全体に自動反映される(ON UPDATE CASCADE設定時) |
| デメリット | SQLiteは接続ごとに有効化が必要 |
PRAGMA foreign_keys = ON;を毎回実行しないと無効のまま動いてしまう |
| デメリット | パフォーマンスへの影響がある | 制約チェックが増えるため、大量データの INSERT・DELETEは若干遅くなる |
| デメリット | 設計の自由度が下がる | 親テーブルを削除・変更する際に子テーブルとの関係を考慮する必要がある |
2. SQLiteの外部キーは初期設定で無効
SQLiteはデフォルトで外部キー制約が無効です。
使用する際は毎回有効化する必要があります。
PRAGMA foreign_keys = ON;
接続のたびに設定が必要です。
Pythonで使用する場合は、DB接続直後に必ず実行してください。
conn = sqlite3.connect("data.db")
conn.execute("PRAGMA foreign_keys = ON;")
3. テーブルの作成
外部キーはREFERENCESで設定します。
-- 親テーブル
CREATE TABLE part (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
-- 子テーブル(外部キーあり)
CREATE TABLE order_table (
id INTEGER PRIMARY KEY,
part_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
FOREIGN KEY (part_id) REFERENCES part(id)
);
4. ON DELETE / ON UPDATE の設定
親テーブルのデータが変更・削除された際の
子テーブルの挙動を指定できます。
| オプション | 挙動 |
|---|---|
CASCADE |
親の変更・削除に合わせて子も変更・削除される |
SET NULL |
親が削除されたら子の外部キー列をNULLにする |
RESTRICT |
子が存在する場合、親の削除・変更を拒否する |
NO ACTION |
何もしない(デフォルト) |
CASCADEの例(親を消したら子も消える)
CREATE TABLE order_table (
id INTEGER PRIMARY KEY,
part_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
FOREIGN KEY (part_id) REFERENCES part(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
この設定により、partテーブルの行を削除すると
対応するorder_tableの行も自動的に削除されます。
SET NULLの例
FOREIGN KEY (part_id) REFERENCES part(id)
ON DELETE SET NULL
SET NULLを使う場合、外部キー列にNOT NULL制約をつけないでください。
NULLを入れられなくなりエラーになります。
5. 動作確認
-- 親テーブルにデータを追加
INSERT INTO part (name) VALUES ('ボルト');
-- 子テーブルにデータを追加
INSERT INTO order_table (part_id, quantity) VALUES (1, 100);
-- 親を削除(CASCADEなら子も消える)
DELETE FROM part WHERE id = 1;
-- 子テーブルを確認(CASCADEなら空になっている)
SELECT * FROM order_table;
まとめ
| 項目 | 内容 |
|---|---|
| 外部キーの有効化 |
PRAGMA foreign_keys = ON;を接続ごとに実行 |
| 基本構文 | FOREIGN KEY (列名) REFERENCES 親テーブル(列名) |
| CASCADE | 親の削除・更新に子を追従させる |
| SET NULL | 親削除時に子の外部キー列をNULLにする |
| RESTRICT | 子が存在する親の削除・更新を拒否する |
外部キーを活用することで、アプリケーション側での
整合性チェックを減らし、DBレベルでデータの一貫性を保てます。
過去のSQLiteの記事