查找顶级家长ID

时间:2017-01-30 14:00:55

标签: sql-server sql-server-2005

在一个表格中,我有两列,如下所示

ID  ParentID
1   0x0
2   1
3   2
9   0x0
5   9
6   5
25  0x0
30  25

如何获得顶级家长ID
结果应该看起来像

ID   TopParentID
3    1
6    9
30   25

3 个答案:

答案 0 :(得分:3)

您可以使用递归CTE:

WITH CTE AS
(
    SELECT *, 1 [Level]
    FROM dbo.YourTable
    UNION ALL
    SELECT A.ID, B.[Parent ID], [Level] + 1
    FROM CTE A
    INNER JOIN dbo.YourTable B
        ON A.[Parent ID] = B.Id
), CTE2 AS
(
    SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY [Level] DESC)
    FROM CTE
    WHERE [Parent ID] <> 0
)
SELECT ID, [Parent ID] [Top Level Parent Id]
FROM CTE2
WHERE RN = 1
OPTION (MAXRECURSION 0)
;

<强> Here is a link with a demo

结果是:

╔════╦═════════════════════╗
║ ID ║ Top Level Parent Id ║
╠════╬═════════════════════╣
║  2 ║                   1 ║
║  3 ║                   1 ║
║  5 ║                   9 ║
║  6 ║                   9 ║
║ 30 ║                  25 ║
╚════╩═════════════════════╝

答案 1 :(得分:3)

又一个较短的CTE:

Interaction.MsgBox(...)

在这里测试:SQL Fiddle

编辑:这个该死的SQLfiddle再次没有反应。测试下面的DDL代码

WITH cte AS(
      SELECT *, id AS topparent 
      FROM t 
      WHERE parentid IS NULL
  UNION ALL
      SELECT t.*, c.topparent 
      FROM t JOIN cte c ON c.id = t.parentid
      WHERE t.id <> t.parentid
)
SELECT * FROM cte

答案 2 :(得分:0)

如果顶级节点始终遵循到单个叶节点的单个路径,则可以通过组合Breadcrumbs和递归CTE来实现所需的结果。以下示例演示了该方法:

CREATE TABLE #Items
(
    ID              INT
    ,[ParentID]     INT
)

INSERT INTO #Items
VALUES
(1,     0x0),
(2,     1),
(3,     2),
(9,     0x0),
(5,     9),
(6,     5),
(25,    0x0),
(30,    25)



;WITH CTE_Breadcrumbs
AS
(
    SELECT      ID
                ,ParentID
                ,CAST(ID AS NVARCHAR(1000)) AS [Path]
                ,LEN(CAST(ID AS NVARCHAR(1000))) AS [PathLength]
                ,ID AS [RootNodeID]
    FROM        #Items
    WHERE       ParentID = 0x0
    UNION ALL
    SELECT       Child.ID
                ,Child.ParentID
                ,CAST(Parent.[Path] + N'\' + CAST(Child.ID AS NVARCHAR(1000)) AS NVARCHAR(1000)) AS [Path]
                ,LEN(CAST(Parent.[Path] + N'\' + CAST(Child.ID AS NVARCHAR(1000)) AS NVARCHAR(1000))) AS [PathLength]
                ,CAST(
                    CASE 
                        WHEN CHARINDEX('\', [Path]) > 0 THEN LEFT([Path], CHARINDEX('\', [Path]) - 1)
                        ELSE Child.ParentID
                    END
                AS INT)  AS [RootNodeID]
    FROM        #Items Child 
    INNER JOIN  CTE_Breadcrumbs Parent ON Child.ParentID = Parent.ID
)
,
CTE_FullPathID
AS
(
    SELECT      [RootNodeID]
                ,MAX([PathLength]) AS [PathFullLength]
    FROM        CTE_Breadcrumbs
    GROUP BY    [RootNodeID]

)
SELECT      CTE_Breadcrumbs.RootNodeID
            ,CAST(
                REVERSE(
                            CASE 
                                WHEN CHARINDEX('\', REVERSE([Path])) > 0 THEN LEFT(REVERSE([Path]), CHARINDEX('\', REVERSE([Path])) - 1)
                                ELSE NULL
                            END
                        )
            AS INT)  AS [LeafNodeID]
            ,CTE_Breadcrumbs.[Path]
FROM        CTE_Breadcrumbs 
INNER JOIN  CTE_FullPathID ON CTE_Breadcrumbs.[RootNodeID] = CTE_FullPathID.[RootNodeID] AND CTE_Breadcrumbs.PathLength = CTE_FullPathID.[PathFullLength]