Reputation: 71
I have a hierarchical table where for each child there is defined a parent id (except of top level child where parent id is null). Now I would like to display each parent id in one line for selected child.
I was trying to use CTE but CTE is adding additional records to initial set. Instead of that I would like to update the initial set (SELECT statement selecting some children) with list of parents.
Example of table (Table1):
ChildID ParentID
A P
P Q
Q Z
B P
C F
F M
M Q
D H
H Y
Y NULL
Z NULL
If initial statement will select C, A, Q from list of children IDs then expected result is following:
Selected Child Parent IDs
C F, M, Q, Z
A P, Q, Z
Q Z
Upvotes: 0
Views: 2361
Reputation: 3783
You were right about doing this with a CTE, but then you have to take all the rows and put them into one column (see cross apply - xml path).
with cte (selected, child, parent) as
(
select s.id, t.*
from @t as t
inner join @selected as s on t.childid = s.id
union all
select cte.selected, t.*
from @t as t
inner join cte on t.childid = cte.parent
where cte.parent is not null
)
select distinct
t.selected as [Selected Child],
left(a.parents,len(a.parents) - 1) as Parents
from cte t
cross apply (select cast(parent + ',' as text)
from cte tt
where t.selected = tt.selected
for xml path('')) a(parents);
With sample data:
declare @t as table
(
childid char(1),
parentid char(1)
);
declare @selected as table
(
id char(1)
);
insert into @t (childid,parentid) values ('a','p'),
('p','q'),
('q','z'),
('b','p'),
('c','f'),
('f','m'),
('m','q'),
('d','h'),
('h','y'),
('y',null),
('z',null);
insert into @selected (id) values ('c'),('a'),('q');
with cte (selected, child, parent) as
(
select s.id, t.*
from @t as t
inner join @selected as s on t.childid = s.id
union all
select cte.selected, t.*
from @t as t
inner join cte on t.childid = cte.parent
where cte.parent is not null
)
select distinct
t.selected as [Selected Child],
left(a.parents,len(a.parents) - 1) as Parents
from cte t
cross apply (select cast(parent + ',' as text)
from cte tt
where t.selected = tt.selected
for xml path('')) a(parents);
Upvotes: 6