I have a simple hierarchy and need to be able to generate a single table that matches EACH item in the table with ALL of its ancestors. (Caps to emphasize that this is not a duplicate question!)
So here's a table:
Select Item='A', Parent=null into Items union
Select Item='B', Parent='A' union
Select Item='C', Parent='A' union
Select Item='D', Parent='B' union
Select Item='E', Parent='B' union
Select Item='F', Parent='C' union
Select Item='G', Parent='C' union
Select Item='H', Parent='D'
Go
... which represents this hierarchy:
A
/ \
B C
/ \ / \
D E F G
/
H
So B has one ancestor (A), and H has 3 ancestors (D,B,A). This is the desired output:
Item | Ancestor
B | A
C | A
D | A
D | B
E | A
E | B
F | A
F | C
G | A
G | C
H | A
H | B
H | D
Using a recursive CTE, I'm able to find all descendants for any ONE item...
Create Function ItemDescendants(@Item char) Returns @result Table(Item char) As Begin
; With AllDescendants as (
Select
Item,
Parent
From Items i
Where Item=@Item
UNION ALL
Select
i.Item,
i.Parent
from Items i
Join AllDescendants a on i.Parent=a.Item
)
Insert into @result (Item)
Select Item from AllDescendants
Where Item<>@Item;
Return;
End
Go
... but then to get the full expanded list, I have to resort to a cursor (yuk!):
Select Item, Parent into #t From Items
Declare @Item char
Declare c Cursor for (Select Item from Items)
Open c
Fetch c into @Item
While (@@Fetch_Status=0) Begin
Insert into #t (Item, Ancestor) Select Item, @Item from dbo.ItemDescendants(@Item)
Fetch c into @Item
End
Close c
Deallocate c
Select Distinct
Item,
Ancestor
From #t
Where Parent is not null
Order by Item,Parent
Drop Table #t
This works, but I would be so much happier if I could do it with a single elegant query. Seems like it should be possible - any ideas?
Assuming I understand you right, it should be as simple as recursing backwards from the leaf nodes (which is easy since the table Items is storing only the leaf nodes):
;with AncestryTree as (
select Item, Parent
from Items
where Parent is not null
union all
select Items.Item, t.Parent
from AncestryTree t
join Items on t.Item = Items.Parent
)
select * from AncestryTree
order by Item, Parent
SQL Fiddle demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With