的grandgrandparent我有一个表像之下:递归SQL - 发现孩子
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
我有很多数据,所以我需要的东西很快。
谢谢。
的grandgrandparent我有一个表像之下:递归SQL - 发现孩子
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
我有很多数据,所以我需要的东西很快。
谢谢。
可以使用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的只是整个表。在递归链中向下传播原始Id
(如origId
)时递归上升到树层次结构。一旦返回空集合,即一旦找到不再有c.ParentID = m.Id
匹配,递归就终止。
为了得到所需的结果,即每Lastancestor
id
,我们需要做的是为获取每id
的最大lvl
(即深度)的记录。这是使用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
你需要的是一个[递归公用表表达式(https://technet.microsoft.com/en-us/library/ms186243(V = SQL.105)的.aspx) – Magnus
和例如来自SO的优秀帮助:http://stackoverflow.com/questions/22909692/sql-server-cte-parent-child-recursive – xQbert
有没有最大深度? – Shnugo