Reputation: 37
I have a table which says when a product was replaced for other and this other product may also appear in this table.
I want to know how can I write a query where given a product, I get the latest available (replaced) product.
Example:
Product_From Product_To
-------------------------
A E
A D
B F
C B
D F
D G
How would be a query to get the following output:
Product_From Product_Final
-------------------------
A E
A F
A G
B F
C F
D F
D G
The product A was replaced for product D and E but product D was replaced for F and G so product A has products E, F & G as "final products".
The problem is that products can have different replacement entries thus I don't know how many JOINS I need...
Upvotes: 2
Views: 55
Reputation: 164194
You can do it with self left join:
select
p1.product_from,
coalesce(p2.product_to, p1.product_to) product_final
from products p1 left join products p2
on p2.product_from = p1.product_to
See the demo.
Results:
> product_from | product_final
> :----------- | :------------
> A | E
> A | F
> A | G
> B | F
> C | F
> D | F
> D | G
Upvotes: 1
Reputation: 1271003
This is a graph-walking problem. A recursive CTE is the solution:
with p as (
select v.*
from (values ('A', 'E'), ('A', 'D'), ('B', 'F'), ('C', 'B'), ('D', 'F'), ('D', 'G')) v(pfrom, pto)
),
cte as (
select pfrom, pto
from p
where not exists (select 1 from p p2 where p2.pfrom = p.pto)
union all
select p.pfrom, cte.pto
from cte join
p
on cte.pfrom = p.pto
)
select *
from cte
order by pfrom, pto;
Here is a db<>fiddle.
Upvotes: 1