web-dev-qa-db-ja.com

外部制約のある複数のテーブルからの削除

複数のテーブルから削除しようとしています。これが私のテーブルの様子です

    A_has_B ---- B ---- C_has_B
(many to many)        (many to many)

BのレコードのIDを指定して、A_has_B、B、およびC_has_Bからすべての行を削除しようとしています。BのIDを参照するA_has_BおよびC_has_Bに外部キーが定義されたinnodbストレージエンジンでMySQLを使用しています。

私は次のように削除を実行しようとしています:

DELETE A_has_B.*, C_has_B.*, B.*

FROM
A

join
B
on (B.B_id = A.B_id)

join
C
on (C.B_id = B.B_id)

where B.B_id IN(1,2, 4);

問題は、クエリを実行すると、mysqlが次のように文句を言うことです。

Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails (`db`.`C`, CONSTRAINT `fk_C` FOREIGN KEY (`B_id`) REFERENCES `B` (`B_id`) ON DELETE NO ACTION ON UPDATE NO)

どうすればこれを修正できますか?

20
F21

最も簡単な方法は、各テーブルから個別に削除することです。

-- Remove all connections from A which reference
-- the B-rows you want to remove
DELETE FROM A_has_B
WHERE B_id IN (1,2,4);

-- Remove all connections from C which reference
-- the B-rows you want to remove
DELETE FROM C_has_B
WHERE B_id IN (1,2,4);

-- Finally remove the B-rows
DELETE FROM B
WHERE B_id IN (1,2,4);

MySQLでは、1つのステートメントで複数のテーブルから削除することもできます。ただし、削除の順序を制御する方法はありません。 手動 から:

外部キー制約があるInnoDBテーブルを含む複数テーブルのDELETEステートメントを使用する場合、MySQLオプティマイザーは親子関係とは異なる順序でテーブルを処理する可能性があります。この場合、ステートメントは失敗し、ロールバックします。代わりに、単一のテーブルから削除し、InnoDBが提供するON DELETE機能に依存して、他のテーブルをそれに応じて変更する必要があります。

30
Markus Jarderot

実際、MySQLでは、外部キー制約のチェックをオフにすることができます

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
--your SQL statements
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;

最初の行のステートメントは、MySQLサーバーに外部キーチェックをオフにし、最後の行はそれらをオフにします再びオン(非常に重要)。覚えておくべき2つのこと:

  • 制約のチェックをオフにすることはかなり危険であり、たとえば本番DBで実行する必要があるものではありません...最も安全な方法は、個別のステートメントを使用することです。
  • 常に制約チェックをオンに戻します
9
Andrey

外部キーに「カスケードの削除」を指定できます。親行を削除すると、mysqlエンジンは関連する子テーブルのレコードを削除します

3

別のステートメントで削除を実行すると、機能します。

0
Tom Squires