CTE to return all items in hierarchy - sql-server

I have a table with a recursive hierarchy (i.e. ID, ParentID). For any item in this hierachy, I want to be able to bring back a list of everything UP AND DOWN the hierarchy along with the level for each row. Assume that a parent can only ever have a single child.
Take for example the following:
ID ParentID
--------------
1 NULL
2 1
3 2
4 NULL
5 4
6 5
Given ID 1, 2, or 3, I want to return:
ID ParentID Level
-----------------------
1 NULL 1
2 1 2
3 2 3
I've done this before, but I can't remember how. I know the solution involves a CTE, I just can't get it right! Any help is appreciated.

;with cte as
(
select *, 1 as level from #t where id = #yourid
union all
select t.*, level - 1
from cte
inner join #t t on cte.parent = t.id
),
cte2 as
(
select * from cte
union all
select t.*, level+1
from cte2
inner join #t t on cte2.id = t.parent
)
select id,parent, ROW_NUMBER() over (order by level) level
from ( select distinct id, parent, level from cte2) v

The most barebones version of the CTE query I could come up with is:
WITH Ancestry (AncestorID, DescendantID)
AS
(
SELECT
ParentID, ID
FROM
dbo.Location
WHERE
ParentID IS NOT NULL
UNION ALL
SELECT
P.AncestorID, C.ID
FROM
dbo.Location C
JOIN
Ancestry P on C.ParentID = P.DescendantID
)
SELECT * FROM Ancestry
The result is a list of all Ancestor/Descendant relationships that exist in the table.
The final "SELECT * FROM Ancestry" can be replaced with something more complex to filter, order, etc.
To include reflexive relationships, the query can be modified by adding two lines to the final SELECT statement:
SELECT * FROM Ancestry
UNION
SELECT ID, ID FROM dbo.Location

;WITH Recursive_CTE AS (
SELECT
child.ExecutiveId,
CAST(child.ExecutiveName as varchar(100)) BusinessUnit,
CAST(NULL as bigint) ParentUnitID,
CAST(NULL as varchar(100)) ParentUnit,
CAST('' as varchar(100)) LVL,
CAST(child.ExecutiveId as varchar(100)) Hierarchy,
1 AS RecursionLevel
FROM Sales_Executive_level child
WHERE ExecutiveId = 4000 --your Id which you want to get all parent node
UNION ALL
SELECT
child.ExecutiveId,
CAST(LVL + child.ExecutiveName as varchar(100)) AS BusinessUnit,
child.ParentExecutiveID,
parent.BusinessUnit ParentUnit,
CAST('' + LVL as varchar(100)) AS LVL,
CAST(Hierarchy + ':' + CAST(child.ExecutiveId as varchar(100)) as varchar(100)) Hierarchy,
RecursionLevel + 1 AS RecursionLevel
FROM Recursive_CTE parent
INNER JOIN Sales_Executive_level child ON child.ParentExecutiveID = parent.ExecutiveId
)
SELECT * FROM Recursive_CTE ORDER BY Hierarchy
OPTION (MAXRECURSION 300);

Related

T-SQL hierarchy query

I have a table with hierarchical data:
This is a sample of data with id, parent id, name, code (which is sometimes not filled), level and isroot column. In real scenario there will be more levels than just 2 but now let's look at the simplified example.
What I need to do is to loop over all records and find rows where id is not filled at any level of the hierarchy:
Rows with id ranging should be returned from 6 till 10 because they do not have code filled in at any point of the hierarchy
Rows from 1 till 5 should not be returned because code was mentioned somewhere in the hierarchy.
How should one solve this problem with T-SQL?
The only solution that came to my mind was recursivity (cte or WHILE) but I what I was trying to implement was too complex and did not solve the problem.
Slightly different than #DhruvJoshi's answer, since it may be useful:
WITH recCTE AS
(
SELECT
id,
parent_id,
CASE WHEN CODE IS NOT NULL THEN 1 ELSE 0 END as code_check,
1 as depth,
CAST(id as VARCHAR(50)) as path
FROM table
WHERE isRootLevel = 1
UNION ALL
SELECT
table.id,
table.parent_id,
CASE WHEN CODE IS NOT NULL OR reccte.code_check = 1 THEN 1 ELSE 0 END,
depth + 1 as depth,
reccte.path + CAST(table.id AS varchar(10)) as path
FROM
recCTE
INNER JOIN table ON
recCTE.ID = table.parent_id
WHERE depth < 20 /*just in case you start cycling/endless looping*/
)
SELECT * FROM recCTE where code_check = 0 ORDER BY path, depth;
Here is another example, for anyone who may still struggling with hierarchical data (like me).
Say we got a following hierarchical structure:
CEO
|-- Sales Director
│ |-- Sales Manager 1
│ `-- Sales Manager 2
`-- Technical Director
|-- Product Manager
|-- R&D Team Lead
`-- QA Team Lead
Using recursive cte to get the level for each node:
with cte as (
select id, parentId, roleName, 1 as lvl from roles where id = 1 -- root node
union all
select r.id, r.parentId, r.roleName, cte.lvl+1 as lvl from roles r -- child nodes
inner join cte on cte.id = r.parentid
)
select * from cte;
To get the path for each node:
with cte as (
select id, roleName, cast(roleName as varchar(200)) as hierPath
from roles where id = 1
union all
select r.id, r.rolename, cast(cte.hierPath + ' / ' + r.rolename as varchar(200)) as hierPath
from roles r
inner join cte on cte.id = r.parentid
)
select * from cte;
Using row_number() and power() to get the sorted hierarchy tree result (parent followed by all of its children, then all the children of each one of those and so on):
with cte as (
select id, roleName, cast(roleName as varchar(200)) as hierPath, 1 as lvl,
row_number()over(partition by parentid order by roleName) / power(10.0,1) as sortNo
from roles where id = 1
union all
select r.id, r.rolename, cast(cte.hierPath + ' / ' + r.rolename as varchar(200)) as hierPath, cte.lvl+1 as lvl,
cte.sortNo + row_number()over(partition by r.parentid order by r.roleName) / power(10.0,cte.lvl+1) as sortNo
from roles r
inner join cte on cte.id = r.parentid
)
select * from cte
order by sortNo;
Setup test data:
create table roles (
id int not null,
parentId int,
roleName varchar(50) not null
);
insert into roles
(id, parentId, roleName)
values
(1, null, 'CEO'),
(2, 1, 'Sales Director'),
(3, 1, 'Technical Director'),
(4, 2, 'Sales Manager 1'),
(5, 2, 'Sales Manager 2'),
(6, 3, 'Product Manager'),
(7, 3, 'R&D Team Lead'),
(8, 3, 'QA Team Lead');
Query like this should work:
; with cte as
(
select id, parent_id,code,parent_id as RootId from tableT where IsRootLevel=1
UNION ALL
select T2.id,T2.parent_id,T2.code,T1.RootId as RootId from tableT T2 join
cte T1 on T1.id=T2.parent_id and IsRootLevel=0
)
,
cte2 as
(select id,MAX(case when code ='' then NULL else code end) over( partition by RootId) as code from cte)
select T1.* from tableT T1 left join cte2 T2
on T1.id=T2.id
where T2.code is NULL
See working demo

How to set an order when using CTE?

I have a table with 2 columns (id, childId). The data is as follows:
1, 2
3, 4
2, null
4, null
I'm using a CTE so that I get the child records:
DECLARE #id TABLE (id int);
INSERT INTO #id SELECT 1;
INSERT INTO #id SELECT 3;
WITH cte AS
(
SELECT id, childId
FROM mytable
WHERE
id IN (SELECT id FROM #id)
UNION ALL
SELECT b.id, b.childId
FROM mytable b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT * FROM cte
The result always come back as:
1, 2
3, 4
4, null
2, null
But I need the result to look like:
1, 2
2, null
3, 4,
4, null
That is, first the anchor records then the records for the recursive sql for each anchor record.
Is this possible?
Add a static value to in anchor query. Then in recursive part add a static value greater than the static value of anchor query. Now the use static value in Order by
Try this
WITH cte AS
(
SELECT 0 as rn, id, childId
FROM mytable
WHERE
id IN (SELECT id FROM #id)
UNION ALL
SELECT 1 as rn,b.id, b.childId
FROM mytable b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT * FROM cte
Order by rn,id
Also consider adding option(Maxrecursion N). By default it just makes only 100 recursions
By Adding a Seq, the results will be displayed in the proper order/nesting
DECLARE #id TABLE (id int);
INSERT INTO #id SELECT 1;
INSERT INTO #id SELECT 3;
WITH cte AS
(
SELECT id, childId
,Seq = cast(100000+Row_Number() over (Order by id) as varchar(500))
FROM mytable
WHERE
id IN (SELECT id FROM #id)
UNION ALL
SELECT b.id, b.childId
,Seq = cast(concat(cte.Seq,'.',100000+Row_Number() over (Order by b.id)) as varchar(500))
FROM mytable b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT * FROM cte
Order By Seq

CTE Query: How to make them in order

I have a table which stores company information and their parent company in a regular hierarchical manner, with companyid, parentid and name.
I just learn CTE query in Sql Server and write this query
WITH tableR (ParentCompanyID, CompanyID, Levels)
AS
(
-- Anchor member definition
SELECT e.ParentCompanyID, e.CompanyID, 0 As Levels
FROM tblCompany AS e
WHERE ParentCompanyID in (9)
UNION ALL
-- Recursive member definition
SELECT e.ParentCompanyID, e.CompanyID, Levels + 1
FROM tblCompany AS e
INNER JOIN tableR AS d
ON e.ParentCompanyID = d.CompanyID
)
-- Statement that executes the CTE
SELECT tabler.Levels, tableR.CompanyID, (left('--------------', (tabler.Levels* 2)) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR Left join tblcompany c on tableR.CompanyId=c.CompanyID
This works fine, except that it first list the Child of ID=9, then it list 1st level child and then level 2 .. and so on, but what I need is to have Child data come just under their parent, so
L0
L1
L2
L1-1
L2-1
....
Is it possible to do? Because if not then I have to do it recursively in C# code I am using.
I try this as well
WITH tableR (ParentCompanyID, CompanyID, Levels, RowNumber)
AS
(
-- Anchor member definition
SELECT e.ParentCompanyID, e.CompanyID, 1 As Levels, CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)) as RowNumber
FROM tblCompany AS e
WHERE ParentCompanyID in (9)
UNION ALL
-- Recursive member definition
SELECT e.ParentCompanyID, e.CompanyID, Levels + 1, CAST(Concat(d.RowNumber, CAST((Row_Number() Over (Order by e.CompanyName) ) as VARCHAR(MAX)) ) as VARCHAR(MAX)) as RowNumber
FROM tblCompany AS e
INNER JOIN tableR AS d
ON e.ParentCompanyID = d.CompanyID
)
-- Statement that executes the CTE
SELECT tabler.Levels, RowNumber, tableR.CompanyID, (left('--------------', ((tabler.Levels - 1)* 2 )) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR Left join tblcompany c on tableR.CompanyId=c.CompanyID order by RowNumber
But it fails with if any Level has more than 9 records.
Try this solution:
DECLARE #Company TABLE
(
CompanyID INT PRIMARY KEY,
Name NVARCHAR(50) NOT NULL,
ParentCompanyID INT NULL
);
INSERT #Company (CompanyID,Name,ParentCompanyID)
VALUES
(8,N'Tomaten',NULL),
(9,N'NON ĂNŞI chars',NULL),
(10,N'Bananen',NULL),
(11,N'Child #1',9),
(12,N'Child #2',9),
(13,N'Child #1.1',11),
(14,N'Child #1.2',11);
DECLARE #ParentCompanyID INT = 9;
WITH RecComp
AS
(
SELECT crt.CompanyID,
crt.Name,
crt.ParentCompanyID,
1 AS Lvl,
N'/' + CONVERT(NVARCHAR(4000),crt.CompanyID) + N'/' AS CompanyNode_AsChar
FROM #Company crt
WHERE crt.ParentCompanyID = #ParentCompanyID
UNION ALL
SELECT cld.CompanyID,
cld.Name,
cld.ParentCompanyID,
prt.Lvl + 1,
prt.CompanyNode_AsChar + CONVERT(NVARCHAR(4000), cld.CompanyID) + N'/'
FROM RecComp prt -- parent
INNER JOIN #Company cld ON prt.CompanyID = cld.ParentCompanyID
)
SELECT *,
CONVERT(HIERARCHYID, CompanyNode_AsChar) AS CompanyNode
FROM RecComp
ORDER BY CompanyNode;
Results:
CompanyID Name ParentCompanyID Lvl CompanyNode_AsChar CompanyNode
--------- ---------- --------------- --- --------------------- -----------
11 Child #1 9 1 /11/ 0xAE
13 Child #1.1 11 2 /11/13/ 0xAF6C
14 Child #1.2 11 2 /11/14/ 0xAF74
12 Child #2 9 1 /12/ 0xB2
Note: SQL Azure Supports Hierarchyid Data Type
Well, the thing ios, you have no ORDER BY clause.
Why not at least try
-- Statement that executes the CTE
SELECT tabler.Levels, tableR.CompanyID, (left('--------------', (tabler.Levels* 2)) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR Left join tblcompany c on tableR.CompanyId=c.CompanyID
ORDER BY tableR.Levels
That said, the display/UI sectioin should probably be taken car of by the UI output, and not by your query.
This almost seems like you wish to diusplay it in a TreeView rather.
Okay, finally I found a solution to issue. In order to get critics and if I am right to help other here it is
WITH tableR (ParentCompanyID, CompanyID, Levels, RowNumber, RowNumber2)
AS
(
-- Anchor member definition
SELECT e.ParentCompanyID, e.CompanyID, 1 As Levels, CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)) as RowNumber,
CAST(
(Left('000', 3-Len(CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)))) + CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)))
As VARCHAR(MAX)
) AS RowNumber2
FROM tblCompany AS e
WHERE ParentCompanyID in (370)
UNION ALL
-- Recursive member definition
SELECT e.ParentCompanyID, e.CompanyID, Levels + 1, CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)) as RowNumber1,
CAST(
Concat(d.RowNumber2,
Left('000', 3-Len(CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)))),
CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx))
) as VARCHAR(MAX)) as RowNumber2
FROM tblCompany AS e
INNER JOIN tableR AS d
ON e.ParentCompanyID = d.CompanyID
)
-- Statement that executes the CTE
SELECT tabler.Levels, RowNumber, RowNumber2, tableR.CompanyID, (left('--------------', ((tabler.Levels - 1)* 2 )) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR Left join tblcompany c on tableR.CompanyId=c.CompanyID order by RowNumber2, CName
Now, here is the explanation:
I add a ROW_NUMBER Function of SQL Server this simply add the counter to each row of query, so it add seperate counter to Anchor query and Recursive query.
But as we have to arrange them, in order I append Parent/Anchor query value to Child, so Anchor query goes 1, 2, 3.. but child goes 11, 12 ... 21 ...
Then I Cast them as String, because in String Order you will have 1, 2, 21, 3 rather than 1, 2, 3, 21 .. so that works fine for me.
Problem Known: it get bowled over when you hit Anchor query output > 10 rows, or infact any row more than 10 rows, as then anchor query give ID as 11, and child goes 111 and confuse the output.
Solution for above problem: I modify my query to use LEFT and append 000, so if I see that I can max of 100 child I put 3 zero if you see 4 then use 0000 and change 3 to 4 in query.
BUT: I strongly recommend answer above as that is the way to do it.
I would like to share this
if you want to order de data... alphabetic and Child data come just under their parent.. create a baseCTE, use row_number instead of CompanyID, call the Anchor query from Base CTE
BASE CTE
ROW_NUMBER() OVER ( PARTITION BY ParentCompanyID ORDER BY CompanyName) as [row_number]
Anchor query
N'/' + CONVERT(NVARCHAR(4000),[row_number]) + N'/' AS CompanyNode_AsChar
Recursive query
prt.CompanyNode_AsChar + CONVERT(NVARCHAR(4000), [row_number]) + N'/'

Order of Recursion (SQL Server CTE)

I can achieve recursion by using SQL Server's With command (CTE).
WITH MyCTE(ParentID,ID,Name,Level)
AS
(
SELECT ManagerID AS ParentID, UserID AS ID, UserName AS Name, 0 AS Level
FROM USERS U
WHERE U.ManagerID IS NULL
UNION ALL
SELECT U.ManagerID AS ParentID, U.UserID AS ID, U.UserName AS Name, H.Level+1 AS Level
FROM USERS U
INNER JOIN MyCTE H ON H.ID = U.ManagerID
)
SELECT ParentID,ID FROM MyCTE
returns
ParentID ID
NULL 1
1 2
1 3
2 4
What I want to achieve is to reverse this result set. Namely,reversing the root node and the deepest child node as,
ParentID ID
NULL 4
4 2
2 1
3 1
Couldn't figure out how to programmatically implement this (preferably by using CTE), like by using a parameter to determine the recursion order etc. Any help is greatly appreciated, thanks.
Edit :
Modified this a bit inserting my first CTE's results into a temp table, then using another recursion I reverse the order as (I know "WHERE T.ID = (SELECT MAX(ID) FROM #tmp)" wont work in a real situation, I also gotta determine the deepest node with the "Level" column, just tried to simplify this for this example),
INSERT INTO #tmp
SELECT ParentID,ID,Level FROM MyCTE
WITH MyCTE2(ParentID,ID,Level)
AS
(
SELECT NULL AS ParentID, ID AS ID, 0 AS Level FROM #tmp T
WHERE T.ID = (SELECT MAX(ID) FROM #tmp)
UNION ALL
SELECT R2.ID AS ParentID, T.ParentID AS ID, R2.Level+1 FROM #tmp T
INNER JOIN MyCTE2 R2 ON R2.ID = T.ID
WHERE T.ParentID IS NOT NULL
)
Original Results (removed the 1,3 pair)
ParentID ID Level
NULL 1 0
1 2 1
2 4 2
Reversed results,
ParentID ID Level
NULL 4 0
4 2 1
2 1 2
Edit 2:
I did something like this,
SELECT TTT.ParentID,TTT.ID,TTT.Level FROM
(
SELECT ParentID,ID,Level FROM MyCTE2
UNION ALL
SELECT TT.ID AS ParentID,TT.ParentID AS ID,(SELECT Level+1 FROM #tmp WHERE ID=TT.ID)
AS Level FROM
(
SELECT ID FROM #tmp
EXCEPT
SELECT ID FROM MyCTE2
)T INNER JOIN #tmp TT ON TT.ID = T.ID
)TTT
ORDER BY TTT.Level
gives,
ParentID ID Level
NULL 4 0
4 2 1
2 1 2
3 1 2
This may contain errors, im not sure yet, just wanted to show to make sure that pair (3,1) is whther correct with level 2 ? Been thinking on this for quite a while now, I might make some silly mistakes.
Sample data
declare #T table
(
ParentID int,
ID int
)
insert into #T values
(NULL, 1),
(1 , 2),
(1 , 3),
(2 , 4)
Recursion from root:
;with C as
(
select ParentID, ID
from #T
where ParentID is null
union all
select T.ParentID, T.ID
from #T as T
inner join C
on T.ParentID = C.ID
)
select *
from C
Result
ParentID ID
----------- -----------
NULL 1
1 2
1 3
2 4
Recursion from leafs:
;with C as
(
select null as PParentID, ID, ParentID
from #T
where ID not in (select ParentID
from #T
where ParentID is not null)
union all
select C.ID, T.ID, T.ParentID
from #T as T
inner join C
on T.ID = C.ParentID
)
select distinct
PParentID as ParentID,
ID
from C
Result:
ParentID ID
----------- -----------
NULL 3
NULL 4
4 2
2 1
3 1
If you have many branches you will have duplicate rows as merge together. Using distinct takes care of that.
To get the levels correct you need to first calculate the level from top down. Store that in a table variable (or temp table) and then use that as the source for leaf->root recursion.
-- Primary key and unique is in there to get the indexes used in the recursion
declare #T2 table
(
ParentID int,
ID int,
Level int,
primary key (ID),
unique(ParentID, ID)
)
;with C as
(
select ParentID, ID, 0 as Level
from #T
where ParentID is null
union all
select T.ParentID, T.ID, Level + 1
from #T as T
inner join C
on T.ParentID = C.ID
)
insert into #T2
select ParentID, ID, Level
from C
;with C as
(
select null as PParentID, ID, ParentID, Level
from #T2
where ID not in (select ParentID
from #T2
where ParentID is not null)
union all
select C.ID, T.ID, T.ParentID, T.Level
from #T2 as T
inner join C
on T.ID = C.ParentID
)
select distinct
PParentID as ParentID,
ID,
max(Level) over() - Level as level
from C
Result:
ParentID ID level
----------- ----------- -----------
NULL 3 1
NULL 4 0
2 1 2
3 1 2
4 2 1
It is possible but a really bad idea to replace #T2 with a multi CTE query. It will kill performance because to first CTE will be rebuilt for each recursion. At least that is my guess of what is happening but believe me it is not fast.

How to show recursive parentID in a single column in SQL

Here is the example structure of the table:
ID Name ParentID
-----------------------
1 Ancestor NULL
2 GrandFather 1
3 GrandMother 1
4 Child 3
I'm trying to write a query that would return
ID Name Family
----------------------------
1 Ancestor
2 GrandFather Ancestor
3 GrandMother Ancestor
4 Child Ancestor^GrandMother
The tricky part is that I want to show the family of all rows and in a top-down order.
If anyone can point me in the right direction, it would be appreciated :)
EDIT :: This is the real query, but it follows the same idea. it returns an error on line : marketparent.family + '^'+ t2.marketGroupName because it cant find marketparent
WITH marketparent ( marketGroupID,parentGroupID, marketGroupName,family)
AS
(
SELECT marketGroupID,
parentGroupID,
marketGroupName,
'' as family
FROM EVE.dbo.invMarketGroups
WHERE parentGroupID IS NULL
UNION ALL
SELECT t2.parentGroupID,
t2.marketGroupID,
t2.marketGroupName,
marketparent.family + '^'+ t2.marketGroupName
FROM EVE.dbo.invMarketGroups as t2
INNER JOIN marketparent as mp
ON mp.marketGroupID = t2.parentGroupID
)
-- Statement using the CTE
SELECT TOP 10 *
FROM marketparent;
You did not specify your DBMS, so I'm assuming PostgreSQL
WITH RECURSIVE fam_tree (id, name, parent, family) as
(
SELECT id,
name,
parentid,
''::text as family
FROM the_unknown_table
WHERE parent IS NULL
UNION ALL
SELECT t2.id,
t2.name,
t2.parentid,
fam_tree.family || '^' || t2.name
FROM the_unknown_table t2
INNER JOIN fam_tree ON fam_tree.id = t2.parentid
)
SELECT *
FROM fam_tree;
This is standard SQL (except for the ::text typecast) that should work with very few changes on most modern DBMS.
Edit:
For SQL Server you would need to replace the standard concatention character with Microsoft's non-standar + (and you need to remove the recursive keyword which is required by the standard but for some strange reason rejected by SQL Server)
WITH fam_tree (id, name, parent, family) as
(
SELECT id,
name,
parentid,
'' as family
FROM the_unknown_table
WHERE parent IS NULL
UNION ALL
SELECT t2.id,
t2.name,
t2.parentid,
fam_tree.family + '^' + t2.name
FROM the_unknown_table t2
INNER JOIN fam_tree ON fam_tree.id = t2.parentid
)
SELECT *
FROM fam_tree;
You can use a recursive Common Table Expression.
declare #T table
(
ID int,
Name nvarchar(15),
ParentID int
);
insert into #T values
(1, N'Ancestor', NULL),
(2, N'GrandFather', 1),
(3, N'GrandMother', 1),
(4, N'Child', 3);
with C as
(
select T.ID,
T.Name,
T.ParentID,
cast(N' ' as nvarchar(max)) as Family
from #T as T
where T.ParentID is null
union all
select T.ID,
T.Name,
T.ParentID,
C.Family+'^'+C.Name
from #T as T
inner join C
on T.ParentID = C.ID
)
select C.ID,
C.Name,
stuff(C.Family, 1, 2, '') as Family
from C;
select T.ID, T.Name, (select name from table where ID=T.ParentID)as Family
from table T

Resources