Reputation: 55
I have a tree structure:
CARS (ID = 3)
| AUDI (ID: 5, ParentId: 3)
| DIR1 (ID: 9, ParentId: 5)
| DIR2 (ID: 7, ParentId: 5)
| DIR3 (ID: 8, ParentId: 5)
| FIAT (ID: 10, ParentId: 3)
| FORD (ID: 11, ParentId: 3)
| DIR4 (ID: 12, ParentId: 11)
| RENAULT (ID: 6, ParentId: 3)
| TOYOTA (ID: 4, ParentId: 3)
I need to display the ID's of all the leaves related to a given level along with this level as follows:
ID | Name | ID2 | Name2 |
---|---|---|---|
3 | CARS | 3 | |
3 | CARS | 5 | AUDI |
3 | CARS | 9 | DIR1 |
3 | CARS | 7 | DIR2 |
3 | CARS | 8 | DIR3 |
3 | CARS | 10 | FIAT |
3 | CARS | 11 | FORD |
3 | CARS | 12 | DIR4 |
3 | CARS | 6 | RENAULT |
3 | CARS | 4 | TOYOTA |
5 | AUDI | 5 | |
5 | AUDI | 9 | DIR1 |
5 | AUDI | 7 | DIR2 |
5 | AUDI | 8 | DIR3 |
9 | DIR1 | 9 | DIR1 |
7 | DIR2 | 7 | DIR2 |
8 | DIR3 | 8 | DIR3 |
10 | FIAT | 10 | |
11 | FORD | 11 | |
11 | FORD | 12 | DIR4 |
12 | DIR4 | 12 | DIR4 |
6 | RENAULT | 6 | |
4 | TOYOTA | 4 |
This is a dynamic structure, users can delete and add leaves so I need a function or procedure.
I have created the following code but maybe there is a better, more elegant way to get the results:
DECLARE @T AS TABLE
(
ID int,
Name varchar(255),
ParentId int,
Level int,
Leaf int
)
INSERT INTO @T
VALUES (3, 'CARS', NULL, 1, 0),
(4, 'TOYOTA', 3, 2, 1),
(5, 'AUDI', 3, 2, 2),
(6, 'RENAULT', 3, 2, 3),
(7, 'DIR2', 5, 3, 1),
(8, 'DIR3', 5, 3, 2),
(9, 'DIR1', 5, 3, 3),
(10, 'FIAT', 3, 2, 4),
(11, 'FORD', 3, 2, 5),
(12, 'DIR4', 11, 3, 1)
;WITH cte1 AS
(
SELECT
ID, Name, ParentId, Level, Leaf
FROM
@T
), cte2 AS
(
SELECT
ID, Name, ParentId, 1 AS [Level],
CAST((RTRIM(LTRIM(STR(ID, 15, 0)))) AS VARCHAR(MAX)) AS Ids
FROM
@T t1
WHERE
ParentId IS NULL
UNION ALL
SELECT
t2.ID, t2.Name, t2.ParentId, M.[level] + 1 AS [Level],
CAST((M.Ids + ',' + RTRIM(LTRIM(STR(t2.ID, 15, 0)))) AS VARCHAR(MAX)) AS Ids
FROM
@T AS t2
JOIN
cte2 AS M ON t2.ParentId = M.ID
)
SELECT
B.ID, B.Name AS Name,
cte2.ID AS ID2, cte2.Name
FROM
cte2
CROSS APPLY
(SELECT Split.a.value('.', 'VARCHAR(1024)') AS gId
FROM
(SELECT
CAST ('<M>' + REPLACE(Ids, ',', '</M><M>') + '</M>' AS XML) AS String) A
CROSS APPLY
String.nodes ('/M') AS Split(a)) AS A
CROSS APPLY
(SELECT CAST(gId as int) AS G_ID) AS G_ID
INNER JOIN
@T B ON B.Id = G_ID
Upvotes: 0
Views: 55
Reputation: 22811
Is it what you are after?
WITH cte AS (
SELECT ID, Name, ID id2, Name Name2, ParentId, 1 AS [Level]
, CAST(STR(ID,15,0) AS VARCHAR(MAX)) AS Ids
FROM tbl
UNION ALL
SELECT m.ID, m.Name, t2.id, t2.name, t2.ParentId, M.[level] + 1
, M.Ids + ',' + STR(t2.ID,15,0)
FROM tbl AS t2
JOIN cte AS M ON t2.ParentId = M.ID2
)
select ID, Name, id2, Name2, level, replace(ids, ' ', '')
from cte
order by id, ids;
All paths from a node.
Upvotes: 1