Reputation: 240
I've been toying with recursive queries and have most of the information I need, but in our schema, we have a setting that can be inherited to the child of a parent. When the child inherits the parent setting, it's own setting is set to NULL. This relationship can span multiple levels (example: 4th child inherits from a parent at the top.
We're using PostgreSQL 10.
An example table of this data looks like:
Customers (there's no actual 'inheritance' column in our schema... that is just to identify those)
id | name | parent_id | customer_settings | inheritance |
---|---|---|---|---|
2 | parent customer A | 1 | 1234501 | not inherited |
3 | child of A sub 1 | 2 | null | inherited |
4 | child of A sub 2 | 2 | 1234502 | not inherited |
5 | child of A2 sub 1 | 4 | null | inherited |
6 | parent customer B | 1 | 1234503 | not inherited |
7 | child of B sub 1 | 6 | 1234504 | not inherited |
8 | child of BS1 sub 1 | 7 | null | inherited |
9 | child of BS1 sub 2 | 7 | null | inherited |
10 | child of BS1S2 sub 1 | 9 | null | inherited |
This describes the following hierarchy path:
What I'm trying to do is create a query that will perform a reverse lookup from the current child row in my select to the parent in order to find the first customer_setting value that would be inherited, leading to a result set that looks more like this:
Customers
id | name | parent_id | customer_settings | inheritance |
---|---|---|---|---|
2 | parent customer A | 1 | 1234501 | not inherited |
3 | child of A sub 1 | 2 | 1234501 | inherited |
4 | child of A sub 2 | 2 | 1234502 | not inherited |
5 | child of A2 sub 1 | 4 | 1234502 | inherited |
6 | parent customer B | 1 | 1234503 | not inherited |
7 | child of B sub 1 | 6 | 1234504 | not inherited |
8 | child of BS1 sub 1 | 7 | 1234504 | inherited |
9 | child of BS1 sub 2 | 7 | 1234504 | inherited |
10 | child of BS1S2 sub 1 | 9 | 1234504 | inherited |
There are many different arrangements within these hierarchies, so there are some variations in how many levels inheritance may be coming from. I'd say as a worst case scenario, if something had to be defined, then 10 levels may cover it.
My main issue here is figuring out how to capture those customer_settings from the above objects when that setting is null. Once I have that value for each row, I can then pull other related settings that further define each of those records.
I can recursively look down the tables in order to collect the parent-child relationships and paths, but I have no idea how to look up the hierarchy in that same manner. I kept ending up with a single sub-query to look at the parent object (ex sub-query: SELECT customer_setting FROM customers WHERE id = parent_id), but I can't seem to figure out what I need to do to look up multiple levels when that first find is null.
I appreciate any help you guys can provide.
Upvotes: 2
Views: 337
Reputation: 71461
You can use a recursive CTE to traverse up the table, and then join the CTE to the original table:
with recursive cte(old, id, parent, s) as (
select id, id, parent_id, customer_settings from customers where customer_settings is null
union all
select c.old, c1.id, c1.parent_id, c1.customer_settings from cte c join customers c1 on c.parent = c1.id where c.s is null
)
select c.id, c.name, c.parent_id, case when c.customer_settings is null then c1.s else c.customer_settings end, c.inheritance from customers c left join cte c1 on c.id = c1.old and c1.s is not null;
Upvotes: 1