删除SQL表中的分层数据

时间:2009-05-19 12:08:39

标签: sql sql-server-2005

我有一张包含分层数据的表格 一个“ParentId”列,用于保存其父级的Id(“ID” - 键列)。

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

怎么做?

由于

8 个答案:

答案 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 + '%'

第二种方法
您可以拥有leftright值,而不仅仅是ParentID。以这种方式执行的插入操作较慢,但选择操作非常快。特别是在处理子树节点时...... http://en.wikipedia.org/wiki/Tree_traversal

第三种方法
如果使用SQL 2005 +

,请检查递归CTE

第四种方法
如果使用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)