SQL:从子级获取父级树层次结构

时间:2019-07-24 06:19:56

标签: sql sql-server

我有一个包含IdParentIdTreeTopParentId的表格。这是一个示例结构:

           0
       ___/ \___
      /         \
    1            4
   / \          / \
  2   7        5   8
 /            /
3            6

输入表:

Id     ParentId      Tree                     TopParentId
---    ----------    --------------------     --------
 1     0              NULL                    NULL
 2     1              NULL                    NULL
 7     1              NULL                    NULL
 3     2              NULL                    NULL
 4     0              NULL                    NULL
 5     4              NULL                    NULL
 6     5              NULL                    NULL
 8     4              NULL                    NULL

这是我通过Id = 3时要寻找的输出

输出:

Id     ParentId      Tree                     TopParentId
---    ----------    --------------------     --------
 1     2              3 > 2 > 1 > 0           0

CTE查询应该能够处理多个ID,例如3,7

输出:

Id     ParentId      Tree                     TopParentId
---    ----------    --------------------     --------
 3     2              3 > 2 > 1 > 0           0
 7     1              7 > 1 > 0               0

最终目标是获取TreeTopParentId列并更新相应的Id

这是我到目前为止尝试过的查询:

WITH CTE AS (
      SELECT Id, ParentId,0 AS [Level], CAST(Id AS varchar(1000)) AS Heirarchy,Id AS TopParentId
      FROM dbo.table
      WHERE Id IN (SELECT Id FROM table WHERE ParentId IS NULL)
      UNION ALL

      SELECT mgr.Id, mgr.ParentId, TASKCTE.[Level] +1 AS [Level], 
            CAST(( CAST(mgr.Id AS VARCHAR(1000)) + '>' + CTE.Heirarchy) AS varchar(1000)) AS Heirarchy, CTE.TopParentId
      FROM CTE
        INNER JOIN dbo.table AS mgr
          ON CTE.Id = mgr.ParentId
    )
    UPDATE t SET t.[LEVEL] = TC.[LEVEL], t.ParentTree = TC.Heirarchy, t.TopParentId = TC.TopParentId
    FROM dbo.table AS t
    JOIN (SELECT * FROM CTE WHERE Id IN(SELECT DISTINCT Id FROM INSERTED) AND ParentId IS NOT NULL) TC
    ON 
    t.Id = TC.Id 

上面的查询有效,但是它的CPU / RAM占用大量内存,因为它是从Parent开始的。我需要从子级开始的CTE,但Tree必须与示例输出完全相同。

2 个答案:

答案 0 :(得分:1)

这似乎起作用:

drop table if exists #t;
with cte as (
    select * from (values
        (1, 0),
        (2, 1),
        (7, 1),
        (3, 2),
        (4, 0),
        (5, 4),
        (6, 5),
        (8, 4)
    )
    as x(ID, ParentID)
)

select *
into #t
from cte;

with cte as (
    select * ,
        ID as [start] ,
        ParentID as [FirstParent] ,
        1 as [level] , 
        cast(ID as varchar(max)) as Tree
    from #t
    where ID in (3, 7)

    union all

    select p.*,
        c.[start] ,
        c.FirstParent ,
        c.[level] + 1 ,
        cast(concat(c.Tree, ' > ', p.ID) as varchar(max))
    from cte as c
    join #t as p
        on c.ParentID = p.ID
), top_level as (
    select *, row_number() over (partition by [start] order by [level] desc) as rn
    from cte
)
select [start] as ID , 
    FirstParent as ParentID , 
    concat(Tree, ' > ', ParentID) ,
    ParentID as TopParentID
from top_level
where rn = 1;

通过说明的方式,第一部分只是创建您的测试数据(提示:如果这样做,由于您减少了摩擦,人们更有可能提供帮助这样做!)。解决方案的实质只是将所需的ID用作递归的“基本情况”,并且递归步骤说“获取上一级的ParentID来查找下一级的ID”。其余的只是为了跟踪起点和终点。

答案 1 :(得分:0)

您只需要创建过程即可获得所需的结果。

尝试此方法或此方法的变体会有所帮助。

Create proc CalculateLevel
( @passid nvarchar(max) )
As
Begin
declare @query nvarchar(max)
set @query = '
WITH CTE AS (
      SELECT Id, ParentId,0 AS [Level], CAST(Id AS varchar(1000)) AS Heirarchy,Id AS TopParentId
      FROM dbo.tab
      WHERE Id IN (SELECT Id FROM tab WHERE ParentId IS NULL)
      UNION ALL

      SELECT mgr.Id, mgr.ParentId, CTE.[Level] +1 AS [Level], 
            CAST(( CAST(mgr.Id AS VARCHAR(1000)) + ''>'' + CTE.Heirarchy) AS varchar(1000)) AS Heirarchy, CTE.TopParentId
      FROM CTE
        INNER JOIN dbo.tab AS mgr
          ON CTE.Id = mgr.ParentId
    )

    UPDATE t SET t.[LEVEL] = TC.[LEVEL], t.ParentTree = TC.Heirarchy, t.TopParentId = TC.TopParentId
    FROM dbo.tab AS t
    JOIN (SELECT * FROM CTE WHERE  ParentId IS NOT NULL) TC
    ON 
    t.Id = TC.Id  where t.id in ( ' + @passid  + ')'

    print @query

  exec sp_executesql @query
End