Sql server 列出特定节点的所有祖先节点或父节点,这些节点位于数据透视表中的每个级别上,数据透视表中的级别作为SQL Server中的属性

Sql server 列出特定节点的所有祖先节点或父节点,这些节点位于数据透视表中的每个级别上,数据透视表中的级别作为SQL Server中的属性,sql-server,tsql,pivot,hierarchy,recursive-cte,Sql Server,Tsql,Pivot,Hierarchy,Recursive Cte,我有一个表'temp',它的id和它的直接父项的id作为列。下表如下: 节点的层次结构可以用树结构表示,如上所述 现在,我想使用递归cte列出数据透视表中所有级别上存在的每个节点的所有祖先节点或父节点,递归cte的属性为Level1、Level2等级别。为了得到这个输出,我计算了非数据透视表中的所有父节点,每个节点相对于其父节点的级别。其sql查询如下所示: WITH ctetable as ( SELECT S.id, S.parent, 1 as level FROM te

我有一个表'temp',它的id和它的直接父项的id作为列。下表如下:

节点的层次结构可以用树结构表示,如上所述

现在,我想使用递归cte列出数据透视表中所有级别上存在的每个节点的所有祖先节点或父节点,递归cte的属性为Level1、Level2等级别。为了得到这个输出,我计算了非数据透视表中的所有父节点,每个节点相对于其父节点的级别。其sql查询如下所示:

WITH ctetable as 
(
    SELECT S.id, S.parent, 1 as level
    FROM temp as S where S.parent is not null
    UNION ALL
    SELECT S2.id, p.parent, p.level + 1
    FROM ctetable AS p JOIN temp as S2 on S2.parent = p.id
)
SELECT * FROM ctetable ORDER BY id;
以上查询的输出如下图所示:

但是,我希望透视递归cte,它在特定节点的每个级别上包含下的父id。比如,对于id=4,它应该分别在Level3、Level2和Level1下显示父id 4、2和1。为此,我编写了以下查询:

WITH ctetable as 
(
    SELECT S.id, S.parent, 1 as level
    FROM temp as S where S.parent is not null
    UNION ALL
    SELECT S2.id, p.parent, p.level + 1
    FROM ctetable AS p JOIN temp as S2 on S2.parent = p.id
)

SELECT      
            myid,
            [pn].[1] AS [Level1],
            [pn].[2] AS [Level2],
            [pn].[3] AS [Level3] 
FROM
     (
         SELECT [a].id,
                [a].id as myid,
                [a].level
         FROM ctetable AS [a]
     ) AS [hn] PIVOT(max([hn].id) FOR [hn].level IN([1],[2],[3])) AS [pn]
但是,输出表不是所需的,因为它包含与特定节点的每个级别下的父id重复的相同id,而应该包含该节点的各个级别下的所有父id。执行上述查询后得到的输出如下:


有人能帮我解决这个问题吗

如果您有已知或最大级别数,并且假设我没有反转您想要的结果

如果您将示例数据和所需结果发布为文本,而不是图像,也是最好的选择

范例

返回

编辑-添加+10000


我添加了+10000以便保持序列

是否有其他不使用xml且可以使用pivot的方法?使用xml、replace和value方法看起来有点复杂。@RajatSaini我肯定有,但是xml部分只是解析一个分隔字符串。如果您的ID和父项都是真正的INT,则可以使用数据类型hierarchyid,但性能可能会受到影响。此外,交叉应用允许横向查询。
WITH ctetable as 
(
    SELECT S.id, S.parent, 1 as level
    FROM temp as S where S.parent is not null
    UNION ALL
    SELECT S2.id, p.parent, p.level + 1
    FROM ctetable AS p JOIN temp as S2 on S2.parent = p.id
)

SELECT      
            myid,
            [pn].[1] AS [Level1],
            [pn].[2] AS [Level2],
            [pn].[3] AS [Level3] 
FROM
     (
         SELECT [a].id,
                [a].id as myid,
                [a].level
         FROM ctetable AS [a]
     ) AS [hn] PIVOT(max([hn].id) FOR [hn].level IN([1],[2],[3])) AS [pn]
Declare @YourTable Table ([id] int,[parent] int)
Insert Into @YourTable Values 
 (1,null)
,(2,1)
,(3,1)
,(7,3)
,(4,2)
,(5,2)
,(6,2)
,(8,4)

;with cteP as (
      Select id
            ,Parent 
            ,PathID = cast(10000+id as varchar(500))
      From   @YourTable
      Where  Parent is Null
      Union  All
      Select id  = r.id
            ,Parent  = r.Parent 
            ,PathID = cast(concat(p.PathID,',',10000+r.id) as varchar(500))
      From   @YourTable r
      Join   cteP p on r.Parent  = p.id)
Select ID
      ,B.*
 From  cteP A
 Cross Apply (
                Select Level1 = xDim.value('/x[1]','int')-10000
                      ,Level2 = xDim.value('/x[2]','int')-10000
                      ,Level3 = xDim.value('/x[3]','int')-10000
                      ,Level4 = xDim.value('/x[4]','int')-10000
                      ,Level5 = xDim.value('/x[5]','int')-10000
                From  (Select Cast('<x>' + replace(PathID,',','</x><x>')+'</x>' as xml) as xDim) as X 
             ) B
  Order By PathID