FOREIGN KEY制約の設定

このレッスンで分かること

  • FK の書き方は 3 通り (列レベル / テーブルレベル / ALTER TABLE で後付け)
  • 制約名は CONSTRAINT fk_子_親 で明示すると後の運用が楽
  • 親テーブルが先、子テーブルが後、というテーブル作成順序が鉄則

FOREIGN KEY制約の設定 とは

テーブル間の関連性を設定するFOREIGN KEY制約について解説します。本レッスンでは、FOREIGN KEY制約の設定 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

なぜ重要か

前回は外部キーの「考え方」を学びましたが、実務では DDL (CREATE TABLE / ALTER TABLE) で実際に FK を書き下せないと意味がありません。書き方には複数のスタイルがあり、それぞれメリットがあります。さらに「テーブル作成時に同時に書く」場合と「後から ALTER TABLE で追加する」場合があり、どちらも頻出パターンなので両方使えるようになりましょう。

3 つの書き方

外部キーの書き方は 3 通りあります。

SQL クエリ

-- 1) カラム定義の中で書く (列レベル) CREATE TABLE orders ( id INT PRIMARY KEY, customer_id INT REFERENCES customers(id) ); -- 2) テーブル末尾でまとめて書く (テーブルレベル) CREATE TABLE orders ( id INT PRIMARY KEY, customer_id INT, FOREIGN KEY (customer_id) REFERENCES customers(id) ); -- 3) ALTER TABLE で後から追加 ALTER TABLE orders ADD CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(id);

書き方 1 は最短で書けて分かりやすい一方、制約名を自分で付けられず DB が自動命名します。 書き方 2 は複数カラムの複合外部キーにも対応でき、テーブル末尾に制約をまとめられるので可読性が高くなります。 書き方 3 は既存テーブルに後から追加するときの手段で、運用中の DB に変更を加える場面で使います。

書き方メリットデメリット
列レベル最短、分かりやすい制約名は自動命名
テーブルレベル複合 FK 可、可読性高少し冗長
ALTER TABLE後付け可、運用中の DB に有効既存データに不整合があると失敗

制約名を付ける利点

SQL クエリ

CREATE TABLE orders ( id INT PRIMARY KEY, customer_id INT, CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(id) );

CONSTRAINT fk_orders_customer のように 明示的な名前 を付けておくと、後で ALTER TABLE orders DROP CONSTRAINT fk_orders_customer; のように削除や変更が容易になります。命名規則は fk_{子テーブル}_{親テーブル} が一般的です。

DDL の流れを図で

diagram (will load when visible)

親テーブルが存在しないと子テーブルの FK 宣言で失敗します。テーブル作成順序は「親が先」が鉄則です。

複合外部キー

複数カラムをまとめて参照する場合は、テーブルレベル記法しか使えません。

SQL クエリ

CREATE TABLE order_items ( order_id INT, line_no INT, product_id INT, PRIMARY KEY (order_id, line_no), FOREIGN KEY (order_id) REFERENCES orders(id) );

外部キーは「子テーブルに張る」「親側は PRIMARY KEY か UNIQUE」「親テーブルが先に存在する」の 3 点を必ず押さえる。

FK を後から ALTER TABLE で追加するとき、既存データに不整合があると追加自体が失敗します。先にデータをクレンジングしてから FK を追加するのが安全です。

DROP / ALTER で外す

後で FK を外したい、付け替えたいときは制約名を使って操作します。

SQL クエリ

-- 既存制約の削除 ALTER TABLE orders DROP CONSTRAINT fk_orders_customer; -- 削除して付け直す (CASCADE オプションを変えたい等) ALTER TABLE orders DROP CONSTRAINT fk_orders_customer; ALTER TABLE orders ADD CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE;

制約名を付けていなかった場合、自動命名された名前 (PostgreSQL なら orders_customer_id_fkey のような形式) を \d orders などで調べてから DROP します。最初から名前を付けておく方が遥かに楽です。

アンチパターン

  • カラム型を親と子で揃え忘れる (INT と BIGINT の混在で意図しないキャストが発生)
  • 親テーブルの参照先カラムに UNIQUE 制約が無く、複数の親候補が存在してしまう
  • 一括 INSERT で FK を活かしたまま大量ロードし、データ投入が極端に遅くなる
  • 制約名を付けず、後で操作対象を特定できない

どれも実務で頻発するハマりポイントです。最初の設計時に潰しておきましょう。

この章のポイント

ここまでの要点 FK は 3 通りの書き方、制約名は明示するのが正解。親 → 子の順で CREATE、複合 FK はテーブルレベル記法。型ミスマッチ・UNIQUE 漏れ・制約名なしの 3 大アンチパターンに注意。

まとめ

  • FK 宣言は列レベル / テーブルレベル / ALTER TABLE の 3 通り
  • 制約名を CONSTRAINT fk_xxx で明示すると後の運用が楽になる
  • 親が先、子が後、というテーブル作成順序は守る
  • 複合 FK はテーブルレベル記法で書く
  • 型ミスマッチや UNIQUE 漏れなどのアンチパターンに注意

次のレッスン

次は ON DELETE/UPDATE ポリシー です。SQLにおける外部キー制約、ON DELETE/UPDATEポリシーについてSQLで実践的に設定・確認します。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. FK 制約の設定 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. FK 制約の設定 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

テーブル構造

schema.sql

CREATE TABLE departments ( id INT PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE employees ( id INT PRIMARY KEY, name TEXT NOT NULL, department_id INT, CONSTRAINT fk_employees_department FOREIGN KEY (department_id) REFERENCES departments(id) ); INSERT INTO departments (id, name) VALUES (1, '営業'), (2, '開発'), (3, '人事'); INSERT INTO employees (id, name, department_id) VALUES (101, '田中', 1), (102, '佐藤', 2), (103, '鈴木', 2), (104, '高橋', 3);

期待される出力

departmentmember_count
開発2
人事1
営業1

ヒント

query.sql
query.sql
学習モード
コードの実行結果
データベースを初期化中...