递归 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
个匹配项,递归就会终止。
要获得所需的结果,即每个 id
的 Lastancestor
,我们需要做的就是获取具有 最大 [=16] 的记录=](即深度)每 id
。这是使用 ROW_NUMBER
window 函数实现的。
我有一个 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
个匹配项,递归就会终止。
要获得所需的结果,即每个 id
的 Lastancestor
,我们需要做的就是获取具有 最大 [=16] 的记录=](即深度)每 id
。这是使用 ROW_NUMBER
window 函数实现的。