9cubed
ブログ | Tailwind | Vite | Python | MariaDB | Node.js | Linux | PowerShell | Docker | Git | その他 | 将棋ウォーズ | 歌の練習
< 前の記事

カレントリード

次の記事 >

NOT NULL 制約と NULL を許容した時の動作

MariaDB

[MariaDB]外部キー制約

公開日:2026-01-13
更新日:2026-01-13

1. 概要

外部キー制約を使用すると、関連するテーブル間のデータの整合性を保つことできます。
例えば、親子関係があるテーブルがあった場合、子レコードがある時に親レコードを削除すると、エラーが発生して、子レコードだけが存在する状態を防ぐことができます。

ちなみに、deleted_at や is_deleted などのカラムを使って論理削除を採用している場合は、外部キー制約を付けても効果がない場合があるので、よく検討してください。

2. 動作確認

カテゴリーテーブル(categories)と記事テーブル(articles)を使用して確認します。
記事にカテゴリーIDを持つため、カテゴリーが親です。

2.1 カテゴリーテーブルの作成

SQL
CREATE DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE TABLE categories (
    id   INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);
INSERT INTO categories (id, name) VALUES (1, 'カテゴリー1'), (2, 'カテゴリー2'), (3, 'カテゴリー3');

2.2 ON DELETE RESTRICT

子レコードがある時に、親レコードの削除を禁止します。削除しようとするとエラーが発生します。
例えば、注文データと注文明細データのように、子レコードだけ存在しても意味がない場合に使用します。

SQL
CREATE TABLE articles (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(255) NOT NULL,
    category_id INT NULL,
    
    CONSTRAINT fk_articles_category  # 外部キー制約名
        FOREIGN KEY (category_id)    # 外部キーのカラム名
        REFERENCES categories(id)    # 外部キーの参照先:テーブル名(カラム名)
        ON DELETE RESTRICT           # 削除時の動作:子レコードがある時に親レコードの削除禁止
);

INSERT INTO articles (title, category_id) VALUES ('記事1-1', 1), ('記事1-2', 1), ('記事2', 2), ('記事3', 3);

次の SQL を実行すると、エラーが発生します。
SQL
DELETE FROM categories WHERE id = 1;
エラー
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test_db`.`articles`, CONSTRAINT `fk_articles_category` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`))

子レコードを削除してから親レコードを削除する場合は、削除できます。
SQL
# カテゴリー1 の記事を削除
DELETE FROM articles WHERE category_id = 1;

# カテゴリー1 を削除
DELETE FROM categories WHERE id = 1;

また、存在しない親の ID を指定して INSERT する場合もエラーになります。
SQL
INSERT INTO articles (title, category_id) VALUES ('記事999', 999);
エラー
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test_db`.`articles`, CONSTRAINT `fk_articles_category` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`))

2.3 ON DELETE SET NULL

子レコードがある時に親レコードを削除した場合、子レコードの外部キーを NULL にして、子レコードだけ存在することを許容します。
例えば、カテゴリーと記事のように、カテゴリーに属さない記事があっても良い場合に使用します。

SQL
CREATE TABLE articles (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(255) NOT NULL,
    category_id INT NULL,
    
    CONSTRAINT fk_articles_category  # 外部キー制約名
        FOREIGN KEY (category_id)    # 外部キーのカラム名
        REFERENCES categories(id)    # 外部キーの参照先:テーブル名(カラム名)
        ON DELETE SET NULL           # 削除時の動作:子レコードの外部キーを NULL にします
);

INSERT INTO articles (title, category_id) VALUES ('記事1-1', 1), ('記事1-2', 1), ('記事2', 2), ('記事3', 3);

次の SQL を実行すると、削除した親レコードを参照していた子レコードの外部キーが NULL になります。
SQL
DELETE FROM categories WHERE id = 1;

SELECT * FROM articles;
実行結果
+----+-----------+-------------+
| id | title     | category_id |
+----+-----------+-------------+
|  1 | 記事1-1   |        NULL |
|  2 | 記事1-2   |        NULL |
|  3 | 記事2     |           2 |
|  4 | 記事3     |           3 |
+----+-----------+-------------+

2.4 ON DELETE CASCADE

親レコードを削除すると、子レコードを自動的に削除します。
例えば、注文データと注文明細データのように、子レコードだけ存在しても意味がない場合に使用します。
ON DELETE RESTRICT では、削除を禁止することで整合性を保ちますが、
ON DELETE CASCADE は、子レコードを自動削除することで整合性を保ちます。

SQL
DELETE FROM categories;
INSERT INTO categories (id, name) VALUES (1, 'カテゴリー1'), (2, 'カテゴリー2'), (3, 'カテゴリー3');

CREATE TABLE articles (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(255) NOT NULL,
    category_id INT NULL,
    
    CONSTRAINT fk_articles_category  # 外部キー制約名
        FOREIGN KEY (category_id)    # 外部キーのカラム名
        REFERENCES categories(id)    # 外部キーの参照先:テーブル名(カラム名)
        ON DELETE CASCADE            # 削除時の動作:子レコードを削除します
);

INSERT INTO articles (title, category_id) VALUES ('記事1-1', 1), ('記事1-2', 1), ('記事2', 2), ('記事3', 3);

DELETE FROM categories WHERE id = 1;

SELECT * FROM articles;
categories を削除したのに、articles の記事1-1 と 記事1-2 も削除されている。
実行結果
+----+---------+-------------+
| id | title   | category_id |
+----+---------+-------------+
| 11 | 記事2   |           2 |
| 12 | 記事3   |           3 |
+----+---------+-------------+

2.5 ON UPDATE CASCADE

親レコードのキーが変更されると、自動的に子レコードのキーも合わせて変更します。
但し、キーを変更することは少ないため、使用頻度は低い。
後から追加することもできるので、キーを変更する必要がないなら、最初は付けない方が良い。

SQL
DELETE FROM categories;
INSERT INTO categories (id, name) VALUES (1, 'カテゴリー1'), (2, 'カテゴリー2'), (3, 'カテゴリー3');

CREATE TABLE articles (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(255) NOT NULL,
    category_id INT NULL,
    
    CONSTRAINT fk_articles_category  # 外部キー制約名
        FOREIGN KEY (category_id)    # 外部キーのカラム名
        REFERENCES categories(id)    # 外部キーの参照先:テーブル名(カラム名)
        ON DELETE RESTRICT           # 削除時の動作:子レコードがある時に親レコードの削除禁止
        ON UPDATE CASCADE            # 更新時の動作:親レコード
);

INSERT INTO articles (title, category_id) VALUES ('記事1-1', 1), ('記事1-2', 1), ('記事2', 2), ('記事3', 3);

UPDATE categories SET id = 999 WHERE id = 1;

SELECT * FROM articles;
実行結果
+----+-----------+-------------+
| id | title     | category_id |
+----+-----------+-------------+
|  5 | 記事1-1   |         999 |
|  6 | 記事1-2   |         999 |
|  7 | 記事2     |           2 |
|  8 | 記事3     |           3 |
+----+-----------+-------------+

2.6 既存のテーブルから外部キー制約の削除と追加

外部キー制約の削除
SQL
ALTER TABLE articles                        # テーブル名
    DROP FOREIGN KEY fk_articles_category;  # 外部キー制約名

外部キー制約の追加
SQL
ALTER TABLE articles
    ADD CONSTRAINT fk_articles_category  # 外部キー制約名
        FOREIGN KEY (category_id)        # 外部キーのカラム名
        REFERENCES categories(id)        # 外部キーの参照先:テーブル名(カラム名)
        ON DELETE RESTRICT;              # 削除時の動作:子レコードがある時に親レコードの削除禁止

次のコマンドで、外部キー制約の有無を確認できます。
SQL
SHOW CREATE TABLE articles;
< 前の記事

カレントリード

次の記事 >

NOT NULL 制約と NULL を許容した時の動作

YouTube X

新着一覧

  • テーブル結合(CROSS JOIN、INNER JOIN、LEFT JOIN)MariaDB
  • 楽観ロック・悲観ロックMariaDB
  • カレントリードMariaDB
  • インデックスMariaDB
  • 論理削除(ソフトデリート)MariaDB
  • awk(オーク)の使い方についてLinux
  • NOT NULL 制約と NULL を許容した時の動作MariaDB
  • 外部キー制約MariaDB
  • MySQL と MariaDB の関係MariaDB
  • Docker で PostgreSQL のコンテナの使用Linux

アーカイブ

  • 2026/01
  • 2025/12
  • 2025/11
  • 2025/10
  • 2025/09
  • 2025/08
  • /00

以前のカテゴリー一覧

  • CakePHP3
  • CentOS7
  • HTML・CSS・JavaScript
  • Haskell
  • JavaScript
  • Kotlin
  • Laravel5
  • PHP
  • Python
  • Ruby
  • RubyOnRails5
  • TypeScript
  • Vue.js
  • Webサーバ講座
  • Webプログラミング講座
  • jQuery
  • linux
  • パソコン講座
  • ブログ
  • プログラミング講座
  • メモ帳作成講座
  • 数学

Copyright © 9cubed. All Rights Reserved.

プライバシーポリシー 利用規約
▲