有一个“ParentId”列,它存储了其父对象的“ID”(关键列)。
当删除一行时,我想要删除所有子项(所有嵌套级别)。
如何实现?
谢谢。
在 SQL Server 中:使用递归查询。给定 CREATE TABLE tmp(Id int, Parent int),使用
WITH x(Id) AS (
SELECT @Id
UNION ALL
SELECT tmp.Id
FROM tmp
JOIN x ON tmp.Parent = x.Id
)
DELETE tmp
FROM x
JOIN tmp ON tmp.Id = x.Id
添加外键约束。以下示例适用于MySQL(语法参考):
ALTER TABLE yourTable
ADD CONSTRAINT makeUpAConstraintName
FOREIGN KEY (ParentID) REFERENCES yourTable (ID)
ON DELETE CASCADE;
这将在数据库级别操作,数据库管理系统将确保一旦删除一行,所有引用该行的行也将被删除。
当行数不太大时,erikkallen的递归方法可行。
这里有一种替代方案,它使用临时表来收集所有子项:
create table #nodes (id int primary key)
insert into #nodes (id) values (@delete_id)
while @@rowcount > 0
insert into #nodes
select distinct child.id
from table child
inner join #nodes parent on child.parentid = parent.id
where child.id not in (select id from #nodes)
delete
from table
where id in (select id from #nodes)
从@delete_id所在的行开始,向下降序排列。where语句是为了防止递归;如果你确定没有递归,可以省略该语句。
取决于你如何存储你的层次结构。如果你只有ParentID,那么这可能不是你采取的最有效方法。为了方便子树操作,你应该有一个额外的列Parents
,它将存储所有父级ID,例如:
/1/20/25/40
通过这种方式,您可以轻松地获取所有子节点:
where Parents like @NodeParents + '%'
第二种方法
除了仅使用ParentID外,您还可以具有left
和right
值。以这种方式进行的插入速度较慢,但选择操作非常快。特别是在处理子树节点时... http://en.wikipedia.org/wiki/Tree_traversal
第三种方法
如果您使用SQL 2005+,请检查递归CTE。
第四种方法
如果您使用SQL 2008,请检查HierarchyID类型。它为您的情况提供了足够的可能性。
http://msdn.microsoft.com/en-us/magazine/cc794278.aspx
像这样向表添加触发器:
创建一个在删除时触发的触发器,如下所示:
create trigger TD_MyTable on myTable for delete as -- 删除一级子项 delete M from deleted D inner join myTable M on D.ID = M.ID
每次删除都会调用同一张表上的删除操作,不断调用触发器。请查阅在线书籍以获取其他规则。可能会有触发器嵌套次数限制。
ST
这取决于你使用的数据库。如果你使用的是Oracle,你可以像这样做:
DELETE FROM Table WHERE ID IN (
SELECT ID FROM Table
START WITH ID = id_to_delete
CONNECT BY PRIOR.ID = ParentID
)
预计时间:
如果没有使用CONNECT BY,那么情况会变得有些棘手。正如其他人所建议的那样,触发器或级联删除约束可能是最简单的方法。