できない.dev

MySQL で「Cannot delete or update a parent row」が出て行を削除できない

エラー 1451 は、削除しようとした行を他テーブルの外部キーが参照しているために出る。
子テーブル側の行を先に処理するか、外部キーに ON DELETE の参照動作を設定すれば解決する。

公開:

要約

Cannot delete or update a parent row: a foreign key constraint fails(エラー 1451)は、削除・更新しようとした行が他のテーブルの外部キーから参照されているときに出る。

外部キーの参照動作を指定しない場合の既定は RESTRICT で、参照されている親の行の削除は拒否される。
子テーブル側を先に処理するか、外部キー定義に ON DELETE の動作を設定するのが解決策である。

よくある原因

  1. 子の行が残っている: 削除したい親の行の主キーを、子テーブルの外部キー列がまだ参照している。
  2. 参照動作が未指定: ON DELETE を指定していない外部キーは RESTRICT 扱いになり、親側の削除・更新が拒否される。
  3. 参照元が不明: テーブルが多いと、どの外部キーが削除を妨げているのか分からなくなる。

解決策

1. 参照元のテーブルを特定する

SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_NAME = 'parent';

エラーメッセージにも制約名と参照元テーブルが表示されるので、まずどの外部キーが原因かを確定する。

2. 子テーブル側を先に処理する

DELETE FROM child WHERE parent_id = 10;
DELETE FROM parent WHERE id = 10;

参照している行が無くなれば、親の行は普通に削除できる。

3. 外部キーに ON DELETE の動作を設定する

ALTER TABLE child
  DROP FOREIGN KEY fk_child_parent,
  ADD CONSTRAINT fk_child_parent
    FOREIGN KEY (parent_id) REFERENCES parent(id)
    ON DELETE CASCADE;

CASCADE は親の削除に合わせて子の行も削除し、SET NULL は子の外部キー列を NULL にする(列が NULL 許容である必要がある)。
どの動作が適切かはデータの性質で決まる(FOREIGN KEY 制約の公式ドキュメント(新しいタブで開く))。

4. 一時的にチェックを外す(移行作業のみ)

SET FOREIGN_KEY_CHECKS = 0;
-- テーブル再作成やデータ移行など
SET FOREIGN_KEY_CHECKS = 1;

参照整合性が壊れたデータを作れてしまうため、日常の削除操作には使わない。
ダンプの取り込みやテーブル定義の作り直しなど、整合性を自分で保証できる場面に限る。

この記事は役立ちましたか?