CASCADE vs RESTRICT vs SET NULL

CASCADE vs RESTRICT vs SET NULL とは

外部キー制約におけるCASCADE、RESTRICT、SET NULLの違いを解説します。本レッスンでは、CASCADE vs RESTRICT vs SET NULL の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

なぜ重要か

前回は ON DELETE / ON UPDATE のポリシーが 5 つあることを学びました。実務では特に CASCADE / RESTRICT / SET NULL の 3 つを目にすることが多く、ここをきちんと使い分けられるかどうかで、データの安全性と運用負荷が大きく変わります。同じテーブルでも子供のような関係 (注文と注文明細) と、履歴のような関係 (顧客と注文) では選ぶべきポリシーが正反対になることもあります。

3 つを並べて比較

diagram (will load when visible)

親が消えたときの子の運命がポリシーごとに違います。同じ親 -> 子の関係でも、ビジネス要件次第で選択は異なります。

具体的なシナリオ

たとえば次の 3 つを考えてみます。

SQL クエリ

-- 1. orders と order_items (注文と明細) -- -> 明細は注文の付属物。注文が消えれば明細も消えるべき CREATE TABLE order_items ( id INT PRIMARY KEY, order_id INT REFERENCES orders(id) ON DELETE CASCADE ); -- 2. customers と orders (顧客と注文履歴) -- -> 注文履歴を残したいので、顧客を消そうとしたら拒否 CREATE TABLE orders ( id INT PRIMARY KEY, customer_id INT REFERENCES customers(id) ON DELETE RESTRICT ); -- 3. users と tasks (担当者と作業) -- -> 担当者が退職しても作業は残す、担当不在にして表示 CREATE TABLE tasks ( id INT PRIMARY KEY, assignee_id INT REFERENCES users(id) ON DELETE SET NULL );

この 3 つはどれも親子関係ですが、ポリシーの選択は 「親の不在を子はどう受け取るべきか」 という業務要件で決まります。

選び方のチートシート

diagram (will load when visible)

判断の軸はシンプルです。子レコードが「親なしでは存在意味がないか」「履歴として残したいか」「担当不在の形で残したいか」のどれかに当てはまります。

注意点

  • SET NULL を使うには、FK 列が NULL を許容している必要があります。NOT NULL 制約と両立しません。
  • CASCADE は連鎖します。orders -> order_items が CASCADE で、customers -> orders も CASCADE だと、顧客削除で明細まで一気に消えます。意図的かを確認しましょう。
  • RESTRICT は安全側ですが、親を消したいときに子を先に消さないといけないので、運用手順が増えます。

比較表

プレーンテキスト

CASCADE RESTRICT SET NULL 親 DELETE 時 子も消える エラーで拒否 子の FK を NULL に 親 UPDATE 時 子も更新される エラーで拒否 子の FK を NULL に 子 FK 列 NOT NULL OK NOT NULL OK NULL 許可必須 典型例 明細, 添付 顧客と注文 担当者, レビュア

CASCADE は「子は親の部分」、RESTRICT は「親は保護対象」、SET NULL は「親不在でも子は独立」。この 3 つの意味合いで使い分けると迷わない。

意図せず CASCADE を選んでしまうと、親削除のたびに膨大な子データが消える事故になりかねません。本番投入前に必ず DELETE のリハーサルをし、影響件数を確認しましょう。

連鎖 CASCADE の落とし穴

CASCADE は親 -> 子だけでなく、子 -> 孫テーブルへもさらに波及します。

SQL クエリ

-- customers -> orders -> order_items が全て CASCADE DELETE FROM customers WHERE id = 1; -- 田中の注文も明細も一気に消える

小さい DB では便利ですが、たとえば 1 顧客に数万件の注文・数十万件の明細がぶら下がっている本番では、1 件の DELETE が数秒〜数十秒のロック時間を発生させることがあります。CASCADE は「設計上の意図」と「物理的なデータ量」両方を念頭に置いて選ぶべきです。

RESTRICT 採用時の運用フロー

RESTRICT を採用すると、親を削除する手順は次のように増えます。

SQL クエリ

-- 1) 子テーブルを先に始末 DELETE FROM orders WHERE customer_id = 1; -- 2) その後で親を削除 DELETE FROM customers WHERE id = 1;

アプリ側にこの順序を強制する責任が出てきますが、その代わり「うっかり親削除で履歴が吹き飛ぶ」事故は確実に防げます。安全性と運用負荷のトレードオフをチーム内で合意してから決めましょう。

SET NULL を選ぶときの設計確認

SET NULL を採用するなら、NULL のときの業務的な意味付けを明確にする必要があります。たとえば tasks.assignee_idNULL なら「未アサイン」と扱うのか「アサイン待ち」と扱うのかで、画面表示やフィルタ条件が変わってきます。NULL を「担当不在」を表すフラグとして使うなら、その意味をテーブルコメントなどで明示しておくと運用が楽です。

まとめ

  • CASCADE は「子は親の付属物」、明細・添付・履歴削除に向く
  • RESTRICT は「親を保護」、顧客・商品マスタなど重要データの誤削除を防ぐ
  • SET NULL は「親なしでも子は存続」、担当者・レビュアなどの関係に向く
  • SET NULL は FK 列が NULL 許可であることが必要
  • CASCADE は孫テーブルまで連鎖するのでデータ量も意識する
  • RESTRICT 採用時は「子を先に消す」運用フローを徹底する

次のレッスン

次は 物理FK vs 論理FK です。物理外部キーと論理外部キーの違いをSQL操作を通して学びます。

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

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

理解度チェック (30 秒)

Q. CASCADE/RESTRICT/SET NULL とは何か、1 文で説明してください。

この章のポイント

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

関連レッスン

テーブル構造

schema.sql

CREATE TABLE users ( id INT PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE tasks ( id INT PRIMARY KEY, title TEXT NOT NULL, assignee_id INT, CONSTRAINT fk_tasks_assignee FOREIGN KEY (assignee_id) REFERENCES users(id) ON DELETE SET NULL ); INSERT INTO users (id, name) VALUES (1, '田中'), (2, '佐藤'), (3, '鈴木'); INSERT INTO tasks (id, title, assignee_id) VALUES (101, '見積もり作成', 1), (102, '請求書送付', 1), (103, '顧客訪問', 2), (104, '報告書レビュー', 3);

期待される出力

idtitleassignee_id
101見積もり作成NULL
102請求書送付NULL
103顧客訪問2
104報告書レビュー3

ヒント

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