【问题标题】:Build Enumeration Path from Adjacency List in SQL从 SQL 中的邻接列表构建枚举路径
【发布时间】:2014-04-29 15:14:59
【问题描述】:

初始场景

我的软件使用树形数据结构,并将其存储在 SQL 中。我使用称为 Adjacency List 的抽象,它由存储IDParentID 的每一行组成。

ID主键ParentID 是同一张表的外键

问题

我想将我的 SQL 抽象“转换”为 路径枚举。它由存储ID 的每一行和一个存储ID 路径的varchar 字段组成,从根到当前行。例如,这棵树中ID = 6 所在行的Path 字段:

应该是/1/2/4/6/。更多详细信息here,名称为 Lineage Column

问题

如何从只有 IDParentID 的现有数据库构建列 Path

【问题讨论】:

  • 我强烈建议不要这样做。将多个值组合到一个字段中是一种强大的 sql 反模式。在不知道您的需求的情况下,我无法确定,但也许将您的邻接列表转换为闭包表或嵌套集对您更有用?两者都没有破坏关系数据结构的原子性。 (另外,我们需要知道您使用的是哪个 RDBMS。有些支持递归,有些以“独特”的方式实现,有些则完全不支持。)
  • @MatBailie,我们只需要检索一个对象及其后代,我们只删除整个子树。我也更喜欢 Closure Table 抽象,但我输了! ;)
  • @LucasReid - 如前所述,您得到的是一个对象及其(Asc)endents,而不是它的(Desc)endents。此外,我们仍然需要了解 RDBMS。
  • 我会再次尝试说服我的团队使用 Closure Tables。出于好奇,我将把这个答案留在这里。
  • 向闭包表中的每一行添加一个depth 字段还允许在必要时按顺序检索路径。

标签: sql sql-server tree hierarchy adjacency-list


【解决方案1】:

SQL Server 2005 及更高版本应支持以下内容:

WITH
  recursed_tree AS
(
  SELECT
    IDObject,
    concat('/', cast(IDObject as varchar(100)))   AS Path
  FROM
    tbObject
  WHERE
    ParentID IS NULL

  UNION ALL

  SELECT
    next.IDObject,
    concat(prev.Path, '/', cast(next.IDObject as varchar(100)))   AS Path
  FROM
    recursed_tree   AS prev
  INNER JOIN
    tbObject        AS next
       ON prev.IDObject = next.ParentID
)

SELECT
  *
FROM
  recursed_tree

【讨论】:

    【解决方案2】:

    我想出了这个 SQL Server 查询:

    [tbObjectHierarchy 有一个名为 IDObject 的 FK 和 PK 和一个名为 Pathvarchar ]

    declare @T  as table (IDObject int, Path varchar(500))
    declare @T2 as table (IDObject int, Path varchar(500))
    
    insert into tbObjectHierarchy(IDObject, Path)
    select o.IDObject, concat('/', cast(o.IDObject as varchar(100)), '/') as Path
    from tbObject as o 
    where o.ParentID is null
    
    insert into @T (IDObject, Path)
    select o.IDObject, concat(h.Path, cast(o.IDObject as varchar(100)), '/') as Path
    from tbObject as o
    inner join tbObjectHierarchy as h
    on o.ParentID = h.IDObject
    
    while exists (select top 1 * from @T)
    begin
        insert into tbObjectHierarchy (IDObject, Path)
        select t.IDObject, t.Path
        from @T as t
    
        delete from @T2
    
        insert into @T2
        select o.IDObject, concat(t.Path, cast(o.IDObject as varchar(100)), '/') as Path
        from tbObject as o
        inner join @T as t
        on o.ParentID = t.IDObject
    
        delete from @T
    
        insert into @T
        select * from @T2
    end
    

    【讨论】:

    • 这显然是 TSQL。是2005以后的版本吗?使用递归 CTE 可能会更简单、更快捷。
    猜你喜欢
    • 2022-01-16
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-03
    相关资源
    最近更新 更多