递归 sql - 找到 child 的祖父母

Recursive sql - find the grandgrandparent of a child

我有一个 table 如下所示:

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

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

我的意思是想要的结果是

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

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

谢谢。

如果有最大深度,您可以使用此方法。您可以通过简单的复制、过去和改编来添加更多的深度级别。我添加了一个数据元素“19,6”以生成一个具有三个祖先的元素和一个具有四个祖先的元素。

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

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

您可以使用 Recursive 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的主播成员就是整个table。递归在树层次结构中向上传播,同时将原始 Id(如 origId)传播到递归链下。一旦返回一个空集,即一旦不再找到 c.ParentID = m.Id 个匹配项,递归就会终止。

要获得所需的结果,即每个 idLastancestor,我们需要做的就是获取具有 最大 [=16] 的记录=](即深度)每 id。这是使用 ROW_NUMBER window 函数实现的。

Demo here