0

我有一张如下表:

Id ParentID 1 99 2 9 3 1 4 2 5 4 6 3

我想要一个查询,为每个孩子提供最后一个祖先。

我的意思是期望的结果是

id Lastancestor 1 99 2 9 3 99 4 9 5 9 6 99

我有很多数据,所以我需要一些快速的东西。

谢谢。

4

2 回答 2

2

您可以使用递归 CTE来完成此操作:

;WITH CTE AS (
  SELECT Id AS origId, ParentID, 0 AS lvl
  FROM mytable

  UNION ALL

  SELECT c.origId AS origId, 
         m.ParentID, lvl = lvl + 1
  FROM CTE AS c
  INNER JOIN mytable AS m ON c.ParentID = m.Id
)
SELECT origId AS id, ParentID AS Lastancestor
FROM (
  SELECT origId, ParentID,
         ROW_NUMBER() OVER (PARTITION BY origId 
                            ORDER BY lvl DESC) AS rn
  FROM CTE) AS t
WHERE t.rn = 1

在这里,CTE 的锚成员就是整个表。递归沿树层次结构向上传播,同时沿递归链向下传播原始Id(as )。origId一旦返回一个空集,即一旦没有c.ParentID = m.Id找到更多匹配,递归就终止。

为了获得所需的结果,即Lastancestorper id,我们需要做的就是获取 per 具有最大 lvl(即深度)的记录id。这是使用ROW_NUMBER窗口函数实现的。

演示在这里

于 2015-09-09T21:08:14.460 回答
0

如果有最大深度,您可以使用这种方法。您可以通过简单的复制和过去添加进一步的深度级别并进行调整。我添加了一个数据元素“19,6”来生成一个具有三个祖先和一个具有四个祖先。

只需将其粘贴到一个空的查询窗口中并执行。适应您的需求...

declare @Test table (Id int, ParentID int)

insert into @Test values
(1,99)
,(2,9)
,(3,1)
,(4,2)
,(5,4)
,(6,3)
,(19,6);


WITH Ancestors1 AS
(
    SELECT Test.*
          ,Ancestor.ParentID AS Anc1ID 
    FROM @Test AS Test
    LEFT JOIN @Test AS Ancestor ON Test.ParentID=Ancestor.Id
)
,Ancestors2 AS
(
    SELECT Ancestors1.*
          , Ancestor.ParentID AS Anc2ID 
    FROM Ancestors1
    LEFT JOIN @Test AS Ancestor ON Ancestors1.Anc1ID=Ancestor.Id
)
,Ancestors3 AS
(
    SELECT Ancestors2.*
          , Ancestor.ParentID AS Anc3ID 
    FROM Ancestors2
    LEFT JOIN @Test AS Ancestor ON Ancestors2.Anc2ID=Ancestor.Id
)
SELECT Id,*
      ,COALESCE(Anc3ID,Anc2ID,Anc1ID,ParentID)  AS LastAncId
FROM Ancestors3
于 2015-09-09T21:05:57.937 回答