Reputation: 13
Is it possible to flatten a hierarchical data like below without knowing the root?
I am thinking of using the below to find the ultimate parent first and then using the recursive hierarchial cte to find the child nodes
select parent,COUNT(*) from test_le where parent!=child group by parent
but again I was wondering if its possible to do it directly
Input
parent,child,parent_catg,child_catg
A A FIN FIN
A B FIN FIN
B B FIN FIN
A C FIN FIN
B C FIN FIN
C C FIN FIN
B D FIN FIN
C D FIN FIN
E E OTH OTH
E F OTH OTH
A G FIN FIN
B G FIN FIN
A H FIN FIN
P P FIN FIN
P Q FIN FIN
Desired Output
ultimate_parent child_nodes
A B,C,D,G,H
E F
P Q
Thanks in advance
Upvotes: 1
Views: 1112
Reputation: 40289
In SQL Server, using a CTE (Common Table Expression) pretty much is "how to access it directly". I loaded your data and attempted to work one up (test code below), but quickly hit a number of issues with your data...
Perhaps more relevant (and I am not sure of the technical terms), but this is not a conventional hierarchy. D is a child of both B and C; and B is a child of A, with C a child of both B and A. As such, "conventional" means of walking through hierarchies will not apply.
My coding attempt is below as a start on addressing the problem, but it will not work given the nature of the data provided.
--CREATE TABLE #MyTable
-- (
-- Parent char(1) not null
-- ,Child char(1) not null
-- ,Parent_catg char(3) not null
-- ,Dhild_catg char(3) not null
-- )
--INSERT #MyTable values
-- ('A', 'A', 'FIN', 'FIN')
-- ,('A', 'B', 'FIN', 'FIN')
-- ,('B', 'B', 'FIN', 'FIN')
-- ,('A', 'C', 'FIN', 'FIN')
-- ,('B', 'C', 'FIN', 'FIN')
-- ,('C', 'C', 'FIN', 'FIN')
-- ,('B', 'D', 'FIN', 'FIN')
-- ,('C', 'D', 'FIN', 'FIN')
-- ,('E', 'E', 'OTH', 'OTH')
-- ,('E', 'F', 'OTH', 'OTH')
-- ,('A', 'G', 'FIN', 'FIN')
-- ,('B', 'G', 'FIN', 'FIN')
-- ,('A', 'H', 'FIN', 'FIN')
-- ,('P', 'P', 'FIN', 'FIN')
-- ,('P', 'Q', 'FIN', 'FIN')
;WITH cte
as (
select
Parent
,Child
from #MyTable
where Child <> Parent
and Parent not in(select Child from #MyTable where Parent <> Child)
union all select
mt.Parent
,mt.Child
from cte
inner join #MyTable mt
on mt.Child = cte.Parent
where mt.Child <> mt.Parent
and cte.Child <> cte.Parent
)
--select *
-- from cte
-- where Child <> Parent
-- order by Parent, Child
select
Parent
,string_agg(Child, ',')
from cte
where Child <> Parent
group by
Parent
Upvotes: 2