假设
Nodes.Position
确定子节点在父节点下的位置,并且是父节点唯一的,而不是全局唯一的。
- 的值
Nodes.Position
不是硬编码的,也不是事先知道的。
- 如果按 排序
Nodes.Position
,第一项是左边的,最后一项是右边的。
- 极端节点的定义是取一个节点的最左边或最右边的子节点得到的一个节点。
解决方案
该解决方案仅使用dbo.Nodes
,因为我无法找到一个解决方案,其中使用闭包表遍历树深度优先会更容易,并且在您的场景中重要的Position
列是 on dbo.Nodes
。您可以从中获取父子 IDdbo.Closure
并加入dbo.Nodes
以获取Position
,但这只会添加一些不必要的连接。
下面的查询是针对最右边的节点,要找到最左边的节点,将排序更改为ASC
。
;WITH
RecCTE AS
(
SELECT
Id,
1 AS NodeLevel
FROM
(
SELECT
N.Id,
ROW_NUMBER() OVER (PARTITION BY N.ParentId ORDER BY N.Position DESC) AS NodeRank
FROM
dbo.Nodes AS N
WHERE
N.ParentId = @Parent
) AS SQ
WHERE
NodeRank = 1
UNION ALL
SELECT
Id,
NodeLevel + 1 AS NodeLevel
FROM
(
SELECT
N.Id,
R.NodeLevel,
ROW_NUMBER() OVER (PARTITION BY N.ParentId ORDER BY N.Position DESC) AS NodeRank
FROM
dbo.Nodes AS N
INNER JOIN RecCTE AS R ON N.ParentId = R.Id
) AS SQ
WHERE
NodeRank = 1
)
SELECT
Id
FROM
RecCTE
WHERE
NodeLevel IN ( SELECT MAX(NodeLevel) FROM RecCTE )
更新:嵌套集解决方案
如果您愿意更改表结构,我建议您在这种情况下查看嵌套集方法。例如,如果您有此表(根据节点位置填充):
CREATE TABLE [dbo].NestedSets
(
Id int NOT NULL PRIMARY KEY CLUSTERED,
LeftNum int NOT NULL,
RightNum int NOT NULL,
PathLength int NOT NULL
)
然后找到你的最左节点应该很简单
SELECT
C.Id
FROM
dbo.NestedSets AS C
INNER JOIN dbo.NestedSets AS P
ON P.LeftNum < C.LeftNum AND P.RightNum > C.RightNum
WHERE
P.Id = @Parent
AND C.LeftNum = C.RightNum - 1
AND C.LeftNum = P.LeftNum + C.PathLength - P.PathLength
最右节点:
SELECT
C.Id
FROM
dbo.NestedSets AS C
INNER JOIN dbo.NestedSets AS P
ON P.LeftNum < C.LeftNum AND P.RightNum > C.RightNum
WHERE
P.Id = @Parent
AND C.LeftNum = C.RightNum - 1
AND C.RightNum = P.RightNum - (C.PathLength - P.PathLength)
我不确定在您的上下文闭包方法中是否比嵌套集更有意义,但出于此查询的目的,差异非常显着。