症状
MySQLでINSERTまたはUPDATE実行時に「Cannot add or update a child row: a foreign key constraint fails」エラーが発生する。
結論:まずこれを確認
- 挿入・更新しようとしている外部キーの値が、参照先テーブルに存在するか確認
- 存在しない場合は、先に参照先テーブルにデータを追加する
- データ型・文字コード・照合順序が一致しているか確認
トラブルシューティングフロー
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 参照整合性」