我有一张包含分层数据的表格 一个“ParentId”列,用于保存其父级的Id(“ID” - 键列)。
删除行时,我想删除所有子项(所有级别的嵌套)。
怎么做?
由于
答案 0 :(得分:9)
在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
答案 1 :(得分:5)
添加外键约束。以下示例适用于MySQL(syntax reference):
ALTER TABLE yourTable
ADD CONSTRAINT makeUpAConstraintName
FOREIGN KEY (ParentID) REFERENCES yourTable (ID)
ON DELETE CASCADE;
这将在数据库级别上运行,dbms将确保删除一行后,所有引用行也将被删除。
答案 2 :(得分:4)
当行数不是太大时,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语句是为了防止递归;如果你确定没有,你可以把它留下来。
答案 3 :(得分:3)
取决于您存储层次结构的方式。如果您只有ParentID,那么它可能不是您采用的最有效的方法。为了便于子树操作,您应该有一个额外的列Parents
,它将存储所有父ID,如:
/1/20/25/40
这样你就可以通过以下方式获得所有子节点:
where Parents like @NodeParents + '%'
第二种方法
您可以拥有left
和right
值,而不仅仅是ParentID。以这种方式执行的插入操作较慢,但选择操作非常快。特别是在处理子树节点时...... http://en.wikipedia.org/wiki/Tree_traversal
第三种方法
如果使用SQL 2005 +
第四种方法
如果使用SQL 2008,请检查HierarchyID类型。它为您的案例提供了足够的可能性。
http://msdn.microsoft.com/en-us/magazine/cc794278.aspx
答案 4 :(得分:2)
像这样添加一个触发器
在myTable上创建触发器TD_MyTable以进行删除 - 删除一个级别的孩子 从已删除的D内连接myTable M中删除M. 在D.ID = M.ID
每次删除都会在同一个表上调用delete,重复调用触发器。在线查看书籍以了解其他规则。触发器可以嵌套的次数可能有限制。
ST
答案 5 :(得分:0)
取决于您的数据库。如果您使用的是Oracle,则可以执行以下操作:
DELETE FROM Table WHERE ID IN (
SELECT ID FROM Table
START WITH ID = id_to_delete
CONNECT BY PRIOR.ID = ParentID
)
ETA:
没有CONNECT BY,它会变得有点棘手。正如其他人所建议的那样,触发器或级联删除约束可能是最简单的。
答案 6 :(得分:0)
你想要的是这些表之间的referential integrity。
答案 7 :(得分:0)