递归查找 PostgreSQL 10 层次结构

Recursively look up PostgreSQL 10 hierarchy

我一直在研究递归查询,并且拥有我需要的大部分信息,但在我们的模式中,我们有一个设置可以继承到 parent 的 child。当 child 继承 parent 设置时,它自己的设置被设置为 NULL。这种关系可以跨越多个级别(例如:第 4 个 child 继承自顶部的 parent。

我们正在使用 PostgreSQL 10。

此数据的示例 table 如下所示:

客户(在我们的模式中没有实际的 'inheritance' 列...这只是为了识别那些)

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

这描述了以下层次结构路径:

我想要做的是创建一个查询,该查询将执行从我的 select 中的当前 child 行到 parent 的反向查找,以便找到第一个 customer_setting 值将被继承,导致结果集看起来更像这样:

客户

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

在这些层次结构中有许多不同的排列方式,因此继承的级别可能会有所不同。我想说的是最坏的情况,如果必须定义某些东西,那么 10 个级别可能会覆盖它。

我这里的主要问题是弄清楚当该设置为空时如何从上面的 object 中捕获那些 customer_settings。一旦我为每一行设置了该值,我就可以提取其他相关设置,进一步定义每条记录。

我可以递归地查看 向下 table 以收集 parent-child 关系和路径,但我不知道如何查找层次结构以相同的方式。我一直以单个 sub-query 来查看 parent object(例如 sub-query: SELECT customer_setting FROM customers WHERE id = parent_id), 但我似乎无法弄清楚当第一个 find 为 null 时我需要做什么才能查看 up 多个级别。

感谢你们提供的任何帮助。

可以使用递归CTE向上遍历table,然后将CTE加入到原来的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;