从表中指向某个记录ID的后代记录中删除后代记录的策略是什么?具体来说,我正在使用PDO,PHP和MySQL 5.0 +。
想象一下包含这些列的类别表:
如果ID为0,则它是根类别。那个id不是主键,请注意 - 可以有很多根类别。
想象一下,它有几层深层,比如食物和庇护所的根类别,然后是那些孩子,以及那些孩子,等等。这些是后代。如果有人要删除蔬菜,那么你可能会认为食物和住所会被留下作为根类别,但胡萝卜会像Beans一样消失。 Mansions and Cabins也会被遗忘,因为它们来自另一棵树。得到它?
编辑:我的错 - 忘记了一个列 - parent_id。这非常重要。
答案 0 :(得分:2)
可能在你的场景中没有选项,但是,用于存储分层数据的嵌套集模型可以使你所描述的操作非常有效。
这篇文章也许有用:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
答案 1 :(得分:1)
一个简单的级联参照完整性应该这样做 - 使用ON DELETE CASCADE声明你的FOREIGN KEY。如果你索引parent_id
,它甚至应该相当高效(这似乎在MySQL中是必需的;其他DBMS通常允许无索引的FK)。
例如:
CREATE TABLE your_table (
id int PRIMARY KEY,
parent_id int DEFAULT NULL,
category_name varchar(45) NOT NULL,
-- Will also create index on parent_id:
CONSTRAINT your_table_fk1 FOREIGN KEY (parent_id) REFERENCES your_table (id)
ON DELETE CASCADE
);
INSERT INTO your_table (id, category_name) VALUES (1, 'Food');
INSERT INTO your_table (id, category_name) VALUES (2, 'Shelter');
INSERT INTO your_table (id, parent_id, category_name) VALUES (3, 1, 'Vegetables');
INSERT INTO your_table (id, parent_id, category_name) VALUES (4, 3, 'Carrots');
INSERT INTO your_table (id, parent_id, category_name) VALUES (5, 3, 'Beans');
INSERT INTO your_table (id, parent_id, category_name) VALUES (7, 2, 'Mansions');
INSERT INTO your_table (id, parent_id, category_name) VALUES (8, 2, 'Cabins');
然后当你执行......
DELETE FROM your_table WHERE category_name = 'Vegetables'
......不仅'蔬菜',还有'胡萝卜'和'豆'将被删除。
这甚至可以递归地进行,所以......
DELETE FROM your_table WHERE category_name = 'Food'
...删除第一级的'Food',第二级删除'Vegetables',第三级删除'Carrots'和'Beans'。
答案 2 :(得分:0)
虽然嵌套集模型功能更强大,但有时下面的递归示例也足够好。
public function deleteCategory($sCatID) {
if (empty($sCatID)) {
return FALSE;
}
// you can get your PDO database connection your own way -- this is my way for my framework
$PDO = $this->data->mysql();
// recursively find all the descendents of this category and delete those too
$sSQL = "
SELECT
`id`
FROM
`categories`
WHERE
`parent_id` = :parent_id;
";
$st = $PDO->prepare($sSQL);
$st->bindValue(':parent_id',$sCatID);
try {
$st->execute();
$rsRows = $st->fetchAll();
foreach($rsRows as $rwRow) {
$sChildCatID = $rwRow['id'];
// note the recursion here!
$this->deleteCategory($sChildCatID);
}
} catch (PDOException $e) {}
unset($st);
// now delete this category
$sSQL = "
DELETE FROM
`categories`
WHERE
`id` = :id
LIMIT 1;
";
$st = $PDO->prepare($sSQL);
$st->bindValue(':id',$sCatID);
try {
$st->execute();
} catch (PDOException $e){}
}