Si vos suppressions en cascade détruisent un produit parce qu'il était membre d'une catégorie qui a été supprimée, c'est que vous avez mal configuré vos clés étrangères. Avec vos tables d'exemple, vous devriez avoir la configuration de table suivante :
CREATE TABLE categories (
id int unsigned not null primary key,
name VARCHAR(255) default null
);
CREATE TABLE products (
id int unsigned not null primary key,
name VARCHAR(255) default null
);
CREATE TABLE categories_products (
category_id int unsigned not null,
product_id int unsigned not null,
PRIMARY KEY (category_id, product_id),
KEY pkey (product_id),
FOREIGN KEY (category_id) REFERENCES categories (id)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (product_id) REFERENCES products (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
De cette façon, vous pouvez supprimer un produit OU une catégorie, et seuls les enregistrements associés dans categories_products mourront à côté. La cascade ne remontera pas plus haut dans l'arbre et ne supprimera pas la table parent produit/catégorie.
par exemple
products: boots, mittens, hats, coats
categories: red, green, blue, white, black
prod/cats: red boots, green mittens, red coats, black hats
Si vous supprimez la catégorie 'rouge', seule l'entrée 'rouge' dans la table des catégories disparaît, ainsi que les deux entrées prod/cats : 'bottes rouges' et 'manteaux rouges'.
La suppression n'ira pas plus loin et ne supprimera pas les catégories "bottes" et "manteaux".
suivi des commentaires :
vous ne comprenez toujours pas comment les suppressions en cascade fonctionnent. Elles n'affectent que les tables dans lesquelles le "on delete cascade" est défini. Dans ce cas, la cascade est définie dans la table "categories_products". Si vous supprimez la catégorie 'rouge', les seuls enregistrements qui seront supprimés en cascade dans categories_products sont ceux où category_id = red
. Il ne touchera pas les enregistrements où 'category_id = blue', et il ne se rendra pas dans la table "products", car il n'y a pas de clé étrangère définie dans cette table.
Voici un exemple plus concret :
categories: products:
+----+------+ +----+---------+
| id | name | | id | name |
+----+------+ +----+---------+
| 1 | red | | 1 | mittens |
| 2 | blue | | 2 | boots |
+---++------+ +----+---------+
products_categories:
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 1 | // red mittens
| 1 | 2 | // blue mittens
| 2 | 1 | // red boots
| 2 | 2 | // blue boots
+------------+-------------+
Disons que vous supprimez la catégorie n° 2 (bleu) :
DELETE FROM categories WHERE (id = 2);
le SGBD examinera toutes les tables qui ont une clé étrangère pointant vers la table 'categories', et supprimera les enregistrements dont l'identifiant correspondant est 2. Comme nous n'avons défini la relation de clé étrangère qu'en products_categories
vous vous retrouvez avec ce tableau une fois la suppression terminée :
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 1 | // red mittens
| 2 | 1 | // red boots
+------------+-------------+
Il n'y a pas de clé étrangère définie dans le products
La cascade ne fonctionnera donc pas à cet endroit, et vous avez toujours des bottes et des moufles dans la liste. Il n'y a simplement plus de "bottes bleues" ni de "moufles bleues".