In one table I have two columns like below
ID ParentID
1 0x0
2 1
3 2
9 0x0
5 9
6 5
25 0x0
30 25
How to get top level parent ID
If the top-level node always follows a single path to a single leaf node, then the desired result can be achieved by combining Breadcrumbs and recursive CTEs. The following example demonstrates the approach:
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]