Reputation: 2785
ID ParentID Name
1 NULL Adobe
2 1 Adobe Flash
3 2 Adobe Flash 1
4 3 Adobe Flash 2
5 4 Adobe Flash 3
6 NULL Visual Studio
7 6 Visual Studio Beginners
8 NULL SQL Server
9 6 Visual Studio Intermediate
10 6 Visual Studio Advanced
I want to write a query that nests 4 levels deep to display the result-set:
1. Adobe
1.1 Adobe Flash
1.1.1 Adobe Flash 2
1.1.1.1 Adobe FLash 3
2. Visual Studio
2.1 Visual Studio Beginners
3. SQL Server
2.2 Visual Studio Intermediate
2.3 Visual Studio Advanced
Any help is greatly appreciated
Upvotes: 0
Views: 397
Reputation: 57976
WITH SelfReferencingTable AS
( SELECT *
FROM ( VALUES
(01, NULL , 'Adobe' ),
(02, 01 , 'Adobe Flash' ),
(03, 02 , 'Adobe Flash 1' ),
(04, 03 , 'Adobe Flash 2' ),
(05, 04 , 'Adobe Flash 3' ),
(06, NULL , 'Visual Studio' ),
(07, 06 , 'Visual Studio Beginners' ),
(08, NULL , 'SQL Server' ),
(09, 06 , 'Visual Studio Intermediate' ),
(10, 06 , 'Visual Studio Advanced' )
) SRT(ID, ParentID, Name)
),
Levels AS
( SELECT SRT.Id, SRT.ParentId, SRT.Name,
0 as Level, -- To control maximum recurrence
-- Concatenate row number order by Id (try with name)
CAST(ROW_NUMBER()
OVER (ORDER BY SRT.ID) AS VARCHAR(MAX)) + '.' AS Path
FROM SelfReferencingTable SRT
WHERE ParentId IS NULL
UNION ALL -- Do the recursion, baby
SELECT SRT.Id, SRT.ParentId, SRT.Name, Level + 1, Levels.Path +
CAST(ROW_NUMBER() OVER (ORDER BY SRT.ID) AS VARCHAR) + '.'
FROM Levels
JOIN SelfReferencingTable SRT
ON SRT.ParentID = Levels.ID
)
SELECT Path, Name
FROM Levels
--WHERE Level < 3 -- If you really need to limit maximum recursion
ORDER BY Path
Results
Path Name
----------- ---------------------
1. Adobe
1.1. Adobe Flash
1.1.1. Adobe Flash 1
1.1.1.1. Adobe Flash 2
1.1.1.1.1. Adobe Flash 3
2. Visual Studio
2.1. Visual Studio Beginners
2.2. Visual Studio Intermediate
2.3. Visual Studio Advanced
3. SQL Server
Upvotes: 2
Reputation: 9149
Some notes before a solution:
This is what I come up with:
WITH tbl AS (
SELECT *
FROM (VALUES (1,NULL,'Adobe')
,(2,1,'Adobe Flash')
,(3,2,'Adobe Flash 1')
,(4,3,'Adobe Flash 2')
,(5,4,'Adobe Flash 3')
,(6,NULL,'Visual Studio')
,(7,6,'Visual Studio Beginners')
,(8,NULL,'SQL Server')
,(9,6,'Visual Studio Intermediate')
,(10,6,'Visual Studio Advanced')) a(ID,ParentID,Name)
)
, initial AS (
SELECT ID
,ParentID
,Name
,CONVERT(VARCHAR(MAX),ISNULL(ID,0)) as Path
,CAST('' AS VARCHAR(MAX)) AS PathGroup
FROM tbl
WHERE ParentID IS NULL
UNION ALL
SELECT tbl.ID
,tbl.ParentID
,tbl.Name
,initial.Path + '.' + CONVERT(VARCHAR(MAX),tbl.ID)
,initial.Path
FROM tbl
INNER JOIN
initial ON tbl.ParentId = initial.ID
)
, middle AS (
SELECT *
,ROW_NUMBER() OVER(PARTITION BY PathGroup ORDER BY Path) rn
FROM initial
)
, final AS (
SELECT ID
,ParentID
,Name
,CONVERT(VARCHAR(MAX),rn) Hierarchy
FROM middle
WHERE ParentID IS NULL
UNION ALL
SELECT middle.ID
,middle.ParentID
,middle.Name
,final.Hierarchy + '.' + CONVERT(VARCHAR(MAX),middle.rn)
FROM middle
INNER JOIN
final ON middle.ParentId = final.ID
)
SELECT Hierarchy
,Name
FROM final
ORDER BY Hierarchy
Upvotes: 2