I’ve looked at half a dozen different answers here on various scenarios that require recursive CTEs and experimented with them, but have been unable to adapt any of them to work in this situation. I just fundamentally don’t understand how recursion works in PostgreSQL.
I’ve got a view person_v
whose simplified contents look like this:
id | parent_id | name
--------------+-----------+----------
1024 | 512 | foo
512 | | bar
900 | 600 | huey
600 | 300 | louie
300 | | dewey
What I need is a query that always returns me the topmost parent_id
of any id
, or the id
itself if parent_id
is NULL
(i.e. empty in the above table). Not an aggregation of all parents either, just the top one.
To be explicit:
Querying for 1024, I’d get 512.
Querying for 512, I’d get 512.
Querying for 900, I’d get 300. (Not 600, so not the immediate parent, but the top parent.)
Querying for 600, I’d get 300.
Querying for 300, I’d get 300.
The parent-child relationships can be any numbers of levels deep, even though the above example only shows two levels of parentage.
I’m fairly certain that this is possible with the help of recursive CTEs instead of using custom functions, but I just can’t grasp how.
2
Answers
Recurse from the search node to the top. Keep track of when you get to a parent that has a null
parent_id
. From that result, select only the rows where you have hit the top:Working fiddle
We take start row (by id) as anchor of recursive query and go up to topmost parent. Topmost parent is row with higher lvl.
You can take parent_id, or coalesce(parent_id,id) where parent is null. The first, in my opinion, is preferable.
See example
demo
for example, full output of recursive query (ranged by id,lvl desc) for pId=900
for pId is null