2
CREATE TABLE [dbo].[Nodes](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Data] [nvarchar](50) NOT NULL,
    [ParentId] [int] NULL,
    [Position] [char](1) NULL,
    CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED (
    [Id] ASC)
)

CREATE TABLE [dbo].[Closure](
    [ParentId] [int] NOT NULL,
    [ChildId] [int] NOT NULL,
    [PathLength] [int] NOT NULL,
    CONSTRAINT [PK_Closure] PRIMARY KEY CLUSTERED(
    [ParentId] ASC,
    [ChildId] ASC )
)

我需要做的是为特定节点获取最右边的节点。

对查询有任何帮助来解决这个问题吗?谢谢。

4

1 回答 1

0

假设

  1. Nodes.Position确定子节点在父节点下的位置,并且是父节点唯一的,而不是全局唯一的。
  2. 的值Nodes.Position不是硬编码的,也不是事先知道的。
  3. 如果按 排序Nodes.Position,第一项是左边的,最后一项是右边的。
  4. 极端节点的定义是取一个节点的最左边或最右边的子节点得到的一个节点。

解决方案

该解决方案仅使用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)

我不确定在您的上下文闭包方法中是否比嵌套集更有意义,但出于此查询的目的,差异非常显着。

于 2012-12-04T12:11:03.203 回答