2009-05-19 92 views
15

我有一个包含分层数据的表。
保存其父项的Id(“ID” - 键列)的列“ParentId”。删除SQL表中的分层数据

当删除一行时,我想删除所有的子级(所有级别的嵌套)。

怎么办?

谢谢

回答

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

取决于您如何存储您的层次结构。如果您只有ParentID,那么它可能不是您采取的最有效的方法。为了便于操纵子树,你应该有一个附加列Parents是wouls存储所有父ID,如:

/1/20/25/40 

这样你就可以简单地通过获得所有子节点:

where Parents like @NodeParents + '%' 

第二种方法
而不仅仅是ParentID您可能也有leftright值。以这种方式插入会更慢,但选择操作速度非常快。特别是随着子树节点打交道时... http://en.wikipedia.org/wiki/Tree_traversal

第三种方法
检查递归CTE的,如果你使用SQL 2005+

第四种方法
如果使用SQL 2008,检查HIERARCHYID型。它为您的案例提供了足够的可能性。 http://msdn.microsoft.com/en-us/magazine/cc794278.aspx

+0

NO,我不想整父母链存储在列,因为不断有家长参与改变。并且很难跟踪所有这些。 不能这样做,因为它是现在? – markiz 2009-05-19 12:16:27

+0

什么是您的层次结构数据的主要操作?它是插入,更新还是读取? – 2009-05-19 12:18:09

+0

我倾向于同意第一种方法 - 我们已经得到了我们正在做同样事情的分层数据表。它有助于摆脱孩子,并且如果您需要对树进行基于路径的处理(例如,必须快速返回父母的所有孩子进行计算),这也会有所帮助。 我们最初尝试使用触发器来保持这一点,但真正发现添加大量数据时的性能影响是令人望而却步的。 – 2009-05-19 13:05:18

2

添加触发器表中这样

创建mytable上进行删除作为 触发TD_MyTable - 删除的一个子级 从删除d内删除M于D.ID加入myTable的中号 = M.ID

每次删除都会调用同一张表上的删除,反复调用触发器。在线检查书籍是否有其他规则。可能会限制触发器可以嵌套的次数。

ST

+0

这些触发器在SQL SERVER 2005 Express中可用? – markiz 2009-05-19 12:21:03

+0

但是我相信他们是你必须自己写的。没有向导。 – souLTower 2009-05-19 12:24:47

+0

我猜触发器会工作,但触发器的问题是,它将在每次删除时被激活,即使在我只想删除一行的情况下也是如此... – markiz 2009-05-19 13:22:30

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,它变得有点棘手。正如其他人所说,触发器或级联删除约束可能是最简单的。

4

添加外键约束。下面的示例适用于MySQL的(syntax reference):

ALTER TABLE yourTable 
ADD CONSTRAINT makeUpAConstraintName 
FOREIGN KEY (ParentID) REFERENCES yourTable (ID) 
ON DELETE CASCADE; 

这将在数据库级别上运行,数据库管理系统将确保一旦行被删除,所有引用行将被删除了。

9

在SQL Server上:使用递归查询。鉴于CREATE TABLE TMP(ID INT,家长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