Link to home
Start Free TrialLog in
Avatar of larisa1970
larisa1970

asked on

CTE to list all children per node in hierarchy

ParentChildTb
ID    Parent
004  003
003  002
002  001
001  001
Desired Output:
Parent Child
001  002
001  003
001  004
002  003
002  004
003  004
I need a query that traverses through a tree and gets all children, grandchildren, etc. per item
Each item can have many children on different levels and each child can have multiple parents.

Thank you!
Avatar of Guy Hengel [angelIII / a3]
Guy Hengel [angelIII / a3]
Flag of Luxembourg image

this should do:
with data as (
  select id, parent from ParentChildTb t where not exists ( select null from ParentChildTb x where x.id = t.Parent )
 UNION ALL
 select t.id, t.parent from ParentChildTb t join data on data.id = t.parentid
)
select * from data

Open in new window

Avatar of larisa1970
larisa1970

ASKER

Angelll,
thanks, but you query doesn't return anything.
It should return more records than in the original table
sorry, I see:
with data as (
  select id, parent from ParentChildTb t where id = parent)
 UNION ALL
 select t.id, t.parent from ParentChildTb t join data on data.id = t.parentid
)
select * from data

Open in new window


"The statement terminated. The maximum recursion 100 has been exhausted before statement completion."
check this.
-- @ParentChildTb1 is your main table
declare @ParentChildTb1 table(ID int,Parent int)
insert @ParentChildTb1 values(4,3)
insert @ParentChildTb1 values(3,2)
insert @ParentChildTb1 values(2,1)
insert @ParentChildTb1 values(1,1)

-- Create a temp table, insert all the records from your main table and update the rool to NULL 
declare @ParentChildTb table(ID int,Parent int)
insert @ParentChildTb select * from @ParentChildTb1
update @ParentChildTb set Parent = NULL where ID = Parent

-- Try this CTE to get the Tree of parents
;WITH cte AS(
SELECT ID, Parent, coalesce(Convert(varchar(max),Parent)+',','') AS Tree
  FROM @ParentChildTb
 WHERE Parent is null
 UNION ALL
SELECT c.ID, c.Parent, p.Tree + ',' + CAST(c.Parent AS varchar(max))
  FROM @ParentChildTb c
  JOIN cte p
    ON c.Parent = p.ID
),cte2 as (
SELECT ID,Parent,SUBSTRING(Tree,2,LEN(Tree)) Tree FROM cte)
-- This query gives the desired output
select ParentID,ID ChildID from (
SELECT ID,ltrim(SUBSTRING(Tree, n, CHARINDEX(',', Tree + ',',n) - n)) AS ParentID
 FROM cte2
CROSS JOIN (SELECT number FROM master..spt_values WHERE type = 'P')  AS Numbers(n)
WHERE SUBSTRING(',' + Tree, n, 1) = ','
  AND n < LEN(Tree) + 1) t1
order by ParentID,ID
/*
ParentID	ChildID
1	2
1	3
1	4
2	3
2	4
3	4
*/

Open in new window

of course...
with data as (
  select id, parent from ParentChildTb t where id = parent)
 UNION ALL
 select t.id, t.parent from ParentChildTb t join data on data.id = t.parentid and t.id <> t.parentid
)
select * from data

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Sharath S
Sharath S
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I would suggest Option #3: Accept one or more comments as the solution.The correct answer would be http:#a34890907
well, when I analyse the question in deep, even Sharath's code will not solve all the scenarios properly without an additional distinct.

>Each item can have many children on different levels and each child can have multiple parents.
this was not in the test case neither, and will result in duplicates.

I presumed the asker was happy with the simple code ...


so my suggestion would be to split between the original accepted comment and Sharath's comment