如何获得极左派&在sql server中使用闭包表的右叶节点

时间:2012-12-03 22:43:44

标签: sql-server closures

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 )
)

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

有关查询的任何帮助以解决此问题?感谢。

1 个答案:

答案 0 :(得分:0)

<强>的假设

  1. Nodes.Position确定父节点下子节点的位置,父节点是唯一的,而不是全局的。
  2. Nodes.Position的值不是硬编码的,事先不知道。
  3. 如果按Nodes.Position排序,则第一项是左项,最后一项是右项。
  4. extreme 节点的定义是,它是通过获取节点的最左侧或最右侧子节点获得的节点。
  5. <强>解

    解决方案仅使用dbo.Nodes,因为我无法找到一个解决方案,其中使用闭包表更容易遍历树深度优先级,并且在您的方案中,重要的Position列已启用dbo.Nodes。您可以从dbo.Closure获取父级和子级ID,然后加入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)
    

    我不确定你的上下文闭包方法是否比嵌套集更有意义,但是为了这个查询的目的,差异非常大。