コンテンツにスキップ

外部キーの定義

D1は、データベース内のテーブル間で外部キー制約を定義および強制することをサポートしています。

外部キー制約を使用すると、テーブル間の関係を強制することができます。たとえば、usersテーブルのuser_idordersテーブルのuser_idの間に厳密なバインディングを作成するために外部キーを使用することができ、存在しないユーザーに対して注文を作成することはできません。

外部キー制約は、他のテーブルの行を参照している行を削除することを防ぐこともできます。たとえば、ordersテーブルの行がusersテーブルの行を参照している場合に、usersテーブルから行を削除することはできません。

デフォルトでは、D1はすべてのクエリおよびマイグレーション内で外部キー制約が有効であることを強制します。これは、SQLiteで各トランザクションのためにPRAGMA foreign_keys = onを設定したときに観察される動作と同じです。

外部キー制約の遅延

D1データベースに対してクエリマイグレーションまたはデータのインポートを実行する際、テーブルの作成やスキーマの変更中に外部キーの検証を無効にする必要がある状況があるかもしれません。

D1の外部キーの強制は、SQLiteのPRAGMA foreign_keys = onディレクティブに相当します。D1はすべてのクエリを暗黙のトランザクション内で実行するため、ユーザーのクエリはクエリやマイグレーション中にこれを変更することはできません。

代わりに、D1はPRAGMA defer_foreign_keys = onまたはoffを呼び出すことを許可し、外部キー制約を一時的に違反することができます(現在のトランザクションの終了まで)。

PRAGMA defer_foreign_keys = offを呼び出しても、現在のトランザクションの外で外部キーの強制は無効になりません。トランザクションの終了時に未解決の外部キー違反がある場合、FOREIGN KEY constraint failedエラーで失敗します。

外部キーの強制を遅延させるには、トランザクションの開始時または制約に違反する変更の前にPRAGMA defer_foreign_keys = onを設定します:

-- このトランザクションで外部キーの強制を遅延させる。
PRAGMA defer_foreign_keys = on
-- CREATE TABLEまたはALTER TABLE / COLUMN文を実行します。
ALTER TABLE users ...
-- トランザクションの終了時に設定されていない場合、これは暗黙的です。
PRAGMA defer_foreign_keys = off

未解決の外部キー制約を解決した直後にPRAGMA defer_foreign_keys = onを明示的に設定することもできます。未解決の外部キー制約がまだある場合、FOREIGN KEY constraint failedエラーが発生し、違反を解決する必要があります。

外部キー関係の定義

外部キー関係は、CREATE TABLEを使用してテーブルを作成する際や、ALTER TABLE文を使用して既存のテーブルに列を追加する際に定義できます。

これを、2つのテーブルを持つeコマースウェブサイトに基づいた例で示します:

  • ユーザーアカウントに関する一般的なプロパティを定義するusersテーブル、ユニークなuser_id識別子を含む。
  • 注文をユーザーテーブルのuser_idにマッピングするordersテーブル。

このマッピングはFOREIGN KEYとして定義され、次のことを保証します:

  • 外部キー制約を違反する行をusersテーブルから削除することはできません。これは、無効なユーザーにマッピングされていない注文が存在することを防ぎます。
  • ordersは常に有効なuser_idに対して定義され、無効(または存在しない)ユーザーを参照する注文が作成されるリスクを軽減します。
CREATE TABLE users (
user_id INTEGER PRIMARY KEY,
email_address TEXT,
name TEXT,
metadata TEXT
)
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
status INTEGER,
item_desc TEXT,
shipped_date INTEGER,
user_who_ordered INTEGER,
FOREIGN KEY(user_who_ordered) REFERENCES users(user_id)
)

テーブルごとに複数の外部キー関係を定義でき、外部キー定義は全体のデータベーススキーマ内の複数のテーブルを参照できます。

外部キーアクション

外部キー定義の一部としてアクションを定義することで、親行への変更を制限または伝播させることができます(REFERENCES table(column))。アクションを定義することで、アプリケーション内での外部キー制約の使用が理解しやすくなり、関連データのクリーンアップやデータが孤立するのを防ぐのに役立ちます。

外部キー関係の一部としてON UPDATEおよび/またはON DELETE句を定義する際に設定できるアクションは5つあります。要件に応じて、ON UPDATEON DELETEに異なるアクションを定義することもできます。

  • CASCADE - 親キーを更新または削除すると、それに関連するすべての子キー(行)が削除されます。
  • RESTRICT - 任意の子キーが親キーを参照している場合、親キーは更新または削除できません。デフォルトの外部キーの強制とは異なり、RESTRICTが適用された関係は即座にエラーを返し、トランザクションの終了時には返しません。
  • SET DEFAULT - 外部キー定義によって参照される子列をスキーマで定義されたDEFAULT値に設定します。子列にDEFAULTが設定されていない場合、このアクションを使用することはできません。
  • SET NULL - 外部キー定義によって参照される子列をSQL NULLに設定します。
  • NO ACTION - 何もしません。

次の例では、usersテーブルからユーザーを削除すると、ON DELETE CASCADEを定義しているため、scoresテーブル内のすべての関連行が削除されます。削除したユーザーのスコアを保持したくない場合は、scoresテーブル内のすべての関連行を削除してください。これにより、他のユーザーがまだ有効なスコアを参照できなくなる可能性があります。

CREATE TABLE users (
user_id INTEGER PRIMARY KEY,
email_address TEXT,
)
CREATE TABLE scores (
score_id INTEGER PRIMARY KEY,
game TEXT,
score INTEGER,
player_id INTEGER,
FOREIGN KEY(player_id) REFERENCES users(user_id) ON DELETE CASCADE
)

次のステップ