MySQL foreign key constraints, cascade delete
我想使用外键来保持完整性并避免孤儿(我已经使用了innoDB)。
如何创建DELETE ON CASCADE的SQL语句?
如果我删除某个类别,那么如何确保它不会删除与其他类别相关的产品。
数据透视表"categories_products"在其他两个表之间创建了多对多关系。
1 2 3 4 5 6 7 8 9 10 11 12 |
如果你的级联删除了一个产品,因为它是一个被杀死的类别的成员,那么你就是不正确地设置了你的外键。给定示例表,您应该具有以下表格设置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | CREATE TABLE categories ( id int unsigned not null primary key, name VARCHAR(255) default null )Engine=InnoDB; CREATE TABLE products ( id int unsigned not null primary key, name VARCHAR(255) default null )Engine=InnoDB; 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 )Engine=InnoDB; |
这样,您可以删除产品或类别,只有categories_products中的关联记录会同时消失。级联不会在树上向上移动并删除父产品/类别表。
例如
1 2 3 4 | products: boots, mittens, hats, coats categories: red, green, blue, white, black prod/cats: red boots, green mittens, red coats, black hats |
如果删除"红色"类别,则只有类别表中的"红色"条目以及两个条目prod / cats:"red boots"和"red coat"。
删除不会进一步级联,也不会删除"靴子"和"大衣"类别。
评论后续:
你仍然误解了级联删除的工作方式。它们仅影响定义"on delete cascade"的表。在这种情况下,级联在"categories_products"表中设置。如果删除"红色"类别,则category_products中将级联删除的唯一记录是
这是一个更具体的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 +------------+-------------+ |
假设您删除了类别#2(蓝色):
DBMS将查看所有具有指向'categories'表的外键的表,并删除匹配id为2的记录。因为我们只在
1 2 3 4 5 6 | +------------+-------------+ | product_id | category_id | +------------+-------------+ | 1 | 1 | // red mittens | 2 | 1 | // red boots +------------+-------------+ |
我对这个问题的答案感到困惑,所以我在MySQL中创建了一个测试用例,希望这会有所帮助
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | -- Schema CREATE TABLE T1 ( `ID` int not null auto_increment, `Label` varchar(50), primary key (`ID`) ); CREATE TABLE T2 ( `ID` int not null auto_increment, `Label` varchar(50), primary key (`ID`) ); CREATE TABLE TT ( `IDT1` int not null, `IDT2` int not null, primary key (`IDT1`,`IDT2`) ); ALTER TABLE `TT` ADD CONSTRAINT `fk_tt_t1` FOREIGN KEY (`IDT1`) REFERENCES `T1`(`ID`) ON DELETE CASCADE, ADD CONSTRAINT `fk_tt_t2` FOREIGN KEY (`IDT2`) REFERENCES `T2`(`ID`) ON DELETE CASCADE; -- Data INSERT INTO `T1` (`Label`) VALUES ('T1V1'),('T1V2'),('T1V3'),('T1V4'); INSERT INTO `T2` (`Label`) VALUES ('T2V1'),('T2V2'),('T2V3'),('T2V4'); INSERT INTO `TT` (`IDT1`,`IDT2`) VALUES (1,1),(1,2),(1,3),(1,4), (2,1),(2,2),(2,3),(2,4), (3,1),(3,2),(3,3),(3,4), (4,1),(4,2),(4,3),(4,4); -- Delete DELETE FROM `T2` WHERE `ID`=4; -- Delete one field, all the associated fields on tt, will be deleted, no change in T1 TRUNCATE `T2`; -- Can't truncate a table with a referenced field DELETE FROM `T2`; -- This will do the job, delete all fields from T2, and all associations from TT, no change in T1 |
我认为(我不确定)外键约束在你的表设计中不会完全符合你的要求。也许最好的办法是定义一个存储过程,它将按照你想要的方式删除一个类别,然后在你想要删除一个类别时调用该过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | CREATE PROCEDURE `DeleteCategory` (IN category_ID INT) LANGUAGE SQL NOT DETERMINISTIC MODIFIES SQL DATA SQL SECURITY DEFINER BEGIN DELETE FROM `products` WHERE `id` IN ( SELECT `products_id` FROM `categories_products` WHERE `categories_id` = category_ID ) ; DELETE FROM `categories` WHERE `id` = category_ID; END |
您还需要将以下外键约束添加到链接表:
1 2 3 4 5 6 7 | ALTER TABLE `categories_products` ADD CONSTRAINT `Constr_categoriesproducts_categories_fk` FOREIGN KEY `categories_fk` (`categories_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `Constr_categoriesproducts_products_fk` FOREIGN KEY `products_fk` (`products_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE |
当然,CONSTRAINT子句也可以出现在CREATE TABLE语句中。
创建这些模式对象后,您可以通过发出