Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting from multiple tables with foreign constraints

Tags:

I am trying to delete from multiple tables. Here's what my tables look like

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

I am trying to delete all rows from A_has_B, B and C_has_B given the ID of a record in B. I am using MySQL with the innodb storage engine with foreign keys defined for A_has_B and C_has_B referencing the IDs in B.

I am trying to perform my delete like so:

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); 

The problem is that when I execute the query, mysql complains:

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) 

How can I go about fixing this?

like image 767
F21 Avatar asked Jul 30 '11 07:07

F21


People also ask

How do you delete a record from multiple tables in SQL?

To remove one or more rows in a table: First, you specify the table name where you want to remove data in the DELETE FROM clause. Second, you put a condition in the WHERE clause to specify which rows to remove. If you omit the WHERE clause, the statement will remove all rows in the table.

Can you have the same foreign key in multiple tables?

A table may have multiple foreign keys, and each foreign key can have a different parent table. Each foreign key is enforced independently by the database system.

Can foreign keys handle deletes and updates?

Foreign keys cannot handle deletes and updates. Explanation: A foreign key is the one which declares that an index in one table is related to that in another and place constraints. It is useful for handling deletes and updates along with row entries.


2 Answers

The simplest way would be to delete from each table individually:

-- 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 also allows you to delete from multiple tables in one statement. But there is no way to control the order of the deletions. From the manual:

If you use a multiple-table DELETE statement involving InnoDB tables for which there are foreign key constraints, the MySQL optimizer might process tables in an order that differs from that of their parent/child relationship. In this case, the statement fails and rolls back. Instead, you should delete from a single table and rely on the ON DELETE capabilities that InnoDB provides to cause the other tables to be modified accordingly.

like image 77
Markus Jarderot Avatar answered Nov 16 '22 23:11

Markus Jarderot


Actually, in MySQL, you can turn off checks for foreign key constraints

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

The statement on the first line forces MySQL server to turn off foreign key checks and the last line turns them back on (very important). Two things to keep in mind:

  • It's fairly dangerous to turn off checks for constraints and isn't something that should be done in, say, a production DB... the safest way is to use separate statements.
  • Always turn the constraint checks back on
like image 38
Andrey Avatar answered Nov 17 '22 00:11

Andrey