I want to use foreign keys to keep the integrity and avoid orphans (I already use innoDB).
How do I make a SQL statment that DELETE ON CASCADE?
If I delete a category then how do I make sure that it would not delete products that also are related to other categories.
The pivot table "categories_products" creates a many-to-many relationship between the two other tables.
categories
- id (INT)
- name (VARCHAR 255)
products
- id
- name
- price
categories_products
- categories_id
- products_id
I think (I'm not certain) that foreign key constraints won't do precisely what you want given your table design. Perhaps the best thing to do is to define a stored procedure that will delete a category the way you want, and then call that procedure whenever you want to delete a category.
You also need to add the following foreign key constraints to the linking table:
The CONSTRAINT clause can, of course, also appear in the CREATE TABLE statement.
Having created these schema objects, you can delete a category and get the behaviour you want by issuing
CALL DeleteCategory(category_ID)
(where category_ID is the category to be deleted), and it will behave how you want. But don't issue a normalDELETE FROM
query, unless you want more standard behaviour (i.e. delete from the linking table only, and leave theproducts
table alone).I got confused by the answer to this question, so I created a test case in MySQL, hope this helps
If your cascading deletes nuke a product because it was a member of a category that was killed, then you've set up your foreign keys improperly. Given your example tables, you should have the following table setup:
This way, you can delete a product OR a category, and only the associated records in categories_products will die alongside. The cascade won't travel farther up the tree and delete the parent product/category table.
e.g.
If you delete the 'red' category, then only the 'red' entry in the categories table dies, as well as the two entries prod/cats: 'red boots' and 'red coats'.
The delete will not cascade any farther and will not take out the 'boots' and 'coats' categories.
comment followup:
you're still misunderstanding how cascaded deletes work. They only affect the tables in which the "on delete cascade" is defined. In this case, the cascade is set in the "categories_products" table. If you delete the 'red' category, the only records that will cascade delete in categories_products are those where
category_id = red
. It won't touch any records where 'category_id = blue', and it would not travel onwards to the "products" table, because there's no foreign key defined in that table.Here's a more concrete example:
Let's say you delete category #2 (blue):
the DBMS will look at all the tables which have a foreign key pointing at the 'categories' table, and delete the records where the matching id is 2. Since we only defined the foreign key relationship in
products_categories
, you end up with this table once the delete completes:There's no foreign key defined in the
products
table, so the cascade will not work there, so you've still got boots and mittens listed. There's just no 'blue boots' and no 'blue mittens' anymore.