我有一张如下表:
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
我有很多数据,所以我需要一些快速的东西。
谢谢。
我有一张如下表:
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
我有很多数据,所以我需要一些快速的东西。
谢谢。
您可以使用递归 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
找到更多匹配,递归就终止。
为了获得所需的结果,即Lastancestor
per id
,我们需要做的就是获取 per 具有最大 lvl
(即深度)的记录id
。这是使用ROW_NUMBER
窗口函数实现的。
如果有最大深度,您可以使用这种方法。您可以通过简单的复制和过去添加进一步的深度级别并进行调整。我添加了一个数据元素“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