外部キーの定義
D1は、データベース内のテーブル間で外部キー制約を定義および強制することをサポートしています。
外部キー制約を使用すると、テーブル間の関係を強制することができます。たとえば、usersテーブルのuser_idとordersテーブルの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 UPDATEとON DELETEに異なるアクションを定義することもできます。
CASCADE- 親キーを更新または削除すると、それに関連するすべての子キー(行)が削除されます。RESTRICT- 任意の子キーが親キーを参照している場合、親キーは更新または削除できません。デフォルトの外部キーの強制とは異なり、RESTRICTが適用された関係は即座にエラーを返し、トランザクションの終了時には返しません。SET DEFAULT- 外部キー定義によって参照される子列をスキーマで定義されたDEFAULT値に設定します。子列にDEFAULTが設定されていない場合、このアクションを使用することはできません。SET NULL- 外部キー定義によって参照される子列をSQLNULLに設定します。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)- SQLiteの
FOREIGN KEY↗ドキュメントを読む。 - Worker内からD1クライアントAPIを使用する方法を学ぶ。
- D1でのデータベースマイグレーションの仕組みを理解する。