症状

MySQLでINSERTまたはUPDATE実行時に「Cannot add or update a child row: a foreign key constraint fails」エラーが発生する。

結論:まずこれを確認

  1. 挿入・更新しようとしている外部キーの値が、参照先テーブルに存在するか確認
  2. 存在しない場合は、先に参照先テーブルにデータを追加する
  3. データ型・文字コード・照合順序が一致しているか確認

トラブルシューティングフロー

    flowchart TD
    A[外部キー制約エラー発生] --> B{エラーメッセージの<br>制約名を確認}
    B --> C[参照先テーブル・カラムを特定]
    C --> D{参照先に該当データ<br>が存在する?}
    D -->|No| E[参照先にデータを追加]
    D -->|Yes| F{データ型は一致?}
    F -->|No| G[カラムのデータ型を修正]
    F -->|Yes| H{文字コード・照合順序<br>は一致?}
    H -->|No| I[文字コードを統一]
    H -->|Yes| J[NULL値や空文字を確認]
    E --> K[再度INSERT/UPDATE実行]
    G --> K
    I --> K
    J --> K
  

よくある原因

  • 参照先にデータが存在しない - 最も多い原因。外部キーの値が親テーブルに未登録
  • データ型の不一致 - INT と BIGINT、UNSIGNED の有無など微妙な違い
  • 文字コードの不一致 - utf8 と utf8mb4 の違いなど
  • 照合順序(COLLATION)の不一致 - utf8_general_ci と utf8_unicode_ci など
  • NULL値の扱い - 外部キーカラムがNOT NULLなのにNULLを挿入しようとしている
  • トランザクション内での順序問題 - 親レコードをCOMMIT前に子レコードを挿入
  • 一時的に制約を無効化した後の再有効化 - 不整合データが残っている状態

確認手順

ステップ1: エラーメッセージから制約名を特定する

    # エラー例
# Cannot add or update a child row: a foreign key constraint fails
# (`database`.`child_table`, CONSTRAINT `fk_parent_id` FOREIGN KEY (`parent_id`) 
# REFERENCES `parent_table` (`id`))
  

🔍 チェックポイント: CONSTRAINT の後の fk_parent_id が制約名、REFERENCES の後が参照先

ステップ2: 外部キー制約の詳細を確認する

    mysql> SHOW CREATE TABLE child_table\G
  

または

    mysql> SELECT 
    CONSTRAINT_NAME,
    TABLE_NAME,
    COLUMN_NAME,
    REFERENCED_TABLE_NAME,
    REFERENCED_COLUMN_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = 'your_database'
AND TABLE_NAME = 'child_table'
AND REFERENCED_TABLE_NAME IS NOT NULL;
  

🔍 チェックポイント: 参照先テーブル名とカラム名が正しく表示される

ステップ3: 参照先にデータが存在するか確認する

    mysql> SELECT id FROM parent_table WHERE id = '挿入しようとしている値';
  

🔍 チェックポイント: 結果が0件なら、参照先にデータがない

ステップ4: データ型を比較する

    mysql> DESCRIBE parent_table;
mysql> DESCRIBE child_table;
  

🔍 チェックポイント: 外部キーカラムと参照先カラムの Type が完全に一致している

ステップ5: 文字コードと照合順序を確認する

    mysql> SELECT 
    TABLE_NAME,
    COLUMN_NAME,
    CHARACTER_SET_NAME,
    COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'your_database'
AND COLUMN_NAME IN ('parent_id', 'id')
AND TABLE_NAME IN ('parent_table', 'child_table');
  

🔍 チェックポイント: CHARACTER_SET_NAME と COLLATION_NAME が両テーブルで一致

ステップ6: 挿入するデータを確認する

    mysql> SELECT * FROM your_insert_data WHERE parent_id NOT IN (SELECT id FROM parent_table);
  

🔍 チェックポイント: 結果が0件なら、すべての外部キー値が参照先に存在する

NG行動(やってはいけないこと)

  • 外部キー制約を無効化してデータを挿入する - データ不整合の原因になる。根本原因を特定すること
  • 制約を削除して対処する - 参照整合性が失われ、将来的な障害につながる
  • エラーを無視してアプリケーション側で握りつぶす - 不整合データが蓄積する
  • 本番環境で SET FOREIGN_KEY_CHECKS=0 を常用する - テスト・移行時の一時的な使用に限定すること

よくある質問(FAQ)

Q1: 一括インポート時に外部キーエラーが大量発生する場合は?

A: インポート順序を確認する。親テーブル → 子テーブルの順でインポートする。または一時的に SET FOREIGN_KEY_CHECKS=0 を設定し、インポート後に SET FOREIGN_KEY_CHECKS=1 で戻し、不整合がないか確認する。

Q2: 外部キー制約を一時的に無効にする方法は?

A: セッション単位で SET FOREIGN_KEY_CHECKS=0; を実行。作業後は必ず SET FOREIGN_KEY_CHECKS=1; で戻す。本番環境での常用は避ける。

Q3: 既存データに不整合がある状態で外部キー制約を追加できない場合は?

A: 先に不整合データを特定して修正する。SELECT * FROM child_table WHERE parent_id NOT IN (SELECT id FROM parent_table); で不整合レコードを抽出し、削除または修正してから制約を追加する。

関連するエラー・症状

準備中

解決しない場合

  • MySQL公式ドキュメント - 外部キー制約
  • 確認すべきログ: MySQLエラーログ(/var/log/mysql/error.log または SHOW VARIABLES LIKE 'log_error'; で場所を確認)
  • 次に調べるキーワード: 「MySQL foreign key data type mismatch」「MySQL InnoDB foreign key」「MySQL 参照整合性」