本文へスキップ
BecomeCoder

SQL テーブル設計 (DDL)コース · 第2章 キーと制約を極める · レッスン9

外部キーと参照整合性 ― 迷子のデータを防ぐ

ブラウザで完結

導入

「この本の著者IDは 99 番」――でも著者テーブルに 99 番なんていない。こういう**存在しない相手を指す「迷子のデータ」**を防ぐのが、外部キー(FOREIGN KEY)と参照整合性です。DB 自身にルールを守らせれば、アプリのバグでおかしなデータが入るのを水際で止められます。

説明

外部キーは「この列の値は、必ず別のテーブルの主キーに実在すること」を DB に約束させる制約です。列 ... REFERENCES 相手テーブル(相手の列) で宣言します。

flowchart LR
    B["book.author_id"] -->|"REFERENCES author(id)<br/>実在する id しか許さない"| A["author.id"]

SQLite の注意: SQLite は外部キーの強制が既定でオフです。効かせるには、最初に PRAGMA foreign_keys = ON; を実行します(このコースの実行環境では毎回先頭で唱えてください)。

初期表示のコードは、author(著者)と book(本)を作り、book.author_id に外部キーを張っています。最後の INSERT は存在しない著者 99 を指すので、参照整合性に違反してエラーになり、その行は入りません。これが「迷子を防ぐ」働きです。

削除時の連動(ON DELETE)。「著者を消したら、その本も一緒に消したい/消させたくない」を指定できます。

author_id INTEGER REFERENCES author(id) ON DELETE CASCADE

ON DELETE CASCADE は「親(著者)を消したら、子(本)も連鎖して消す」。ON DELETE RESTRICT なら「子がいる親は消させない」。用途に応じて選びます。

やってみよう

初期表示のコードを実行してください。最後の行(著者99番を指す本)で FOREIGN KEY constraint failed のようなエラーが出れば成功です。参照整合性が働いた証拠です。次に、その最後の INSERT991(実在する夏目)に変えて実行すると、今度はエラーなく入ることを確かめましょう。

演習

まず PRAGMA foreign_keys = ON; を唱えたうえで、category2(id・name)と item(id・name・category_idcategory2(id) を参照)を作ってください。そして category2 に何も入れないまま、itemcategory_id = 1 の行を入れて、参照違反のエラーになることを確かめてください。

ヒント1を見る

category_id INTEGER REFERENCES category2(id) と宣言します。親に 1 番がいないので、子の挿入は弾かれます。

ヒント2を見る

PRAGMA foreign_keys = ON; を先頭に書き忘れると、SQLite では制約が効かず素通りしてしまいます。

実際に動かしてみよう

下のエディタにクエリを書いて「実行」を押すと、ブラウザ内のSQLiteで結果が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう。

SQL — ブラウザ内で実行(SQLite)

ブラウザ内でSQLを動かす環境(SQLite)を読み込みます(初回のみ一瞬)。
スクロールして表示された時点でも自動で読み込まれます。