在一个表格中,我有两列,如下所示
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
答案 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]