Reputation: 2326
I have a basic sql table with an ID and an optional parentID from the same table. This has multiple levels. I need to get a list of all IDs with each of its parents all the way to the top.
ID | Name | ParentID
_______________________
1 John null
2 Doe 1
3 Mike 1
4 Neil 3
5 Sylvia 4
6 Mary 2
I need to get a list like this:
ID | Parent | DirectParent
_______________________
2 1 1
3 1 1
4 3 1
4 1 0
5 4 1
5 3 0
5 1 0
How can I query the above table to get this data?
Upvotes: 0
Views: 1096
Reputation: 4802
A recursive CTE will do the job here. The trickiest part is to get the direct parent bit column, hopefully I understood the logic correctly from the expected result. And as a bonus I added an actual reporting hierarchy column for all possible paths. (Recursive depth is up to 10 times here)
CREATE TABLE #MyTable
(
ID int primary key,
Name nvarchar (max),
ParentID int
)
INSERT INTO #MyTable
Values (1, 'John', null),
(2, 'Doe', 1),
(3, 'Mike', 1),
(4, 'Neil', 3),
(5, 'Sylvia', 4),
(6, 'Mary', 2)
WITH FindRoot AS
(
SELECT ID, ParentId, ParentId as Parent, CAST(Name AS NVARCHAR(MAX)) Path, 0 Distance
FROM #MyTable
UNION ALL
SELECT P.ID, p.ParentId, c.Parent, C.Path + N' > ' + CAST(Name AS NVARCHAR(MAX)), C.Distance + 1
FROM #MyTable P
JOIN FindRoot C
ON C.ID = P.ParentId AND P.ParentId <> P.ID and C.ParentId <> c.ID
WHERE C.DISTANCE < 10
)
SELECT R.ID, R.Parent,
CASE WHEN R1.Parent IS NULL THEN 1
ELSE 0
END AS DirectParent, R.Path as ReportingHierarchy
FROM FindRoot R
LEFT JOIN FindRoot R1 on R1.ID = R.ID and R1.Parent =
(SELECT Top 1 Parent From FindRoot
WHERE ID = R.ID and Parent > R.Parent
Order by Parent)
WHERE R.Distance >= 0 and R.ParentId is not null
Order by R.ID, R.distance
option(maxrecursion 10)
Results as follows:
+----+--------+--------------+----------------------+
| ID | Parent | DirectParent | ReportingHierarchy |
+----+--------+--------------+----------------------+
| 2 | 1 | 1 | Doe |
| 3 | 1 | 1 | Mike |
| 4 | 3 | 1 | Neil |
| 4 | 1 | 0 | Mike > Neil |
| 5 | 4 | 1 | Sylvia |
| 5 | 3 | 0 | Neil > Sylvia |
| 5 | 1 | 0 | Mike > Neil > Sylvia |
| 6 | 2 | 1 | Mary |
| 6 | 1 | 0 | Doe > Mary |
+----+--------+--------------+----------------------+
EDIT:
Should have probably mentioned this, but as per comment on this answer - make sure you have your ParentID
and ID
columns indexed.
Upvotes: 2