I am trying to perform what I believe is a difficult recursion using a CTE is SQL Server 2008. I can't seem to wrap my head around this one.
In the below examples you can assume a fixed depth of 3...nothing will ever be lower than that. In real life, the depth is "deeper" but still fixed. In the example I tried to simplify it some.
My input data is like the below.
ID PARENT_ID NAME DEPTH
------------------------------------------
1 NULL A 1
2 1 B 2
3 2 C 3
4 1 D 2
The output of my CTE should be the following table.
LEVEL1_ID LEVEL2_ID LEVEL3_ID LEVEL1_NAME LEVEL2_NAME LEVEL3_NAME
--------------------------------------------------------------------------------
1 NULL NULL A NULL NULL
1 2 NULL A B NULL
1 2 3 A B C
1 4 NULL A D NULL
If I can get the ID columns in the output I can certainly map to names in a lookup table.
I am open to other ways of accomplishing this as well, including using SSIS.
Not really all that hard to do:
;WITH cte AS
(
SELECT CAST('/' + Name AS VARCHAR(50)) as 'CteName', ID
FROM dbo.YourTable
WHERE parent_id IS NULL
UNION ALL
SELECT CAST(cte.CteName + '/' + Name AS VARCHAR(50)), t.ID
FROM dbo.YourTable t
INNER JOIN cte ON t.parent_id = cte.id
)
SELECT cteName FROM cte
ORDER BY ID
Gives me an output of:
/A
/A/B
/A/B/C
/A/D
As a side-note: the "depth" could be easily computed by the CTE and you don't necessarily need to store that in your table (see the Level
column I've added):
;WITH cte AS
(
SELECT
CAST('/' + Name AS VARCHAR(50)) as 'CteName', ID,
1 AS 'Level'
FROM dbo.YourTable
WHERE parent_id IS NULL
UNION ALL
SELECT
CAST(cte.CteName + '/' + Name AS VARCHAR(50)), t.ID,
cte.Level + 1 AS 'Level'
FROM dbo.YourTable t
INNER JOIN cte ON t.parent_id = cte.id
)
SELECT cteName FROM cte
ORDER BY Level, ID
I don't remember of you can do a subquery in a cte.
I don't have a copy of sql server here but you can try with this code:
WITH cte(id, path, level)
AS
(
SELECT id, '/' + name, level
FROM yourtable
WHERE level = 1
UNION ALL
SELECT y.id, c.name + '/' + y.name, y.level
FROM yourtable y INNER JOIN
cte c ON c.id = y.parent_id
WHERE level = (SELECT max(level)+1 from cte)
)
SELECT path from cte
;WITH Vals AS (
SELECT CASE DEPTH WHEN 1 THEN ID ELSE NULL END 'LEVEL1_ID ',
CASE DEPTH WHEN 2 THEN ID ELSE NULL END 'LEVEL2_ID ',
CASE DEPTH WHEN 3 THEN ID ELSE NULL END 'LEVEL3_ID ',
CASE DEPTH WHEN 1 THEN NAME ELSE NULL END 'LEVEL1_NAME',
CASE DEPTH WHEN 2 THEN NAME ELSE NULL END 'LEVEL2_NAME',
CASE DEPTH WHEN 3 THEN NAME ELSE NULL END 'LEVEL3_NAME',
ID 'PRMID'
FROM #Table1
WHERE parentId IS NULL
UNION ALL
SELECT CASE DEPTH WHEN 1 THEN ID ELSE LEVEL1_ID END 'LEVEL1_ID ',
CASE DEPTH WHEN 2 THEN ID ELSE LEVEL2_ID END 'LEVEL2_ID ',
CASE DEPTH WHEN 3 THEN ID ELSE LEVEL3_ID END 'LEVEL3_ID ',
CASE DEPTH WHEN 1 THEN NAME ELSE LEVEL1_NAME END 'LEVEL1_NAME',
CASE DEPTH WHEN 2 THEN NAME ELSE LEVEL2_NAME END 'LEVEL2_NAME',
CASE DEPTH WHEN 3 THEN NAME ELSE LEVEL3_NAME END 'LEVEL3_NAME',
ID 'PRMID'
FROM #Table1 inner join Vals on #Table1.parentId=PRMID
)
SELECT * from Vals