具有分层 parents 最小值的 Postgresql select 列
Postgresql select column with minimum value of hierarchical parents
有这样的table
Table "public.access_level"
Column | Type | Modifiers | Storage | Stats target | Description
-----------+---------+-----------+----------+--------------+-------------
uid | uuid | not null | plain | |
parent_id | integer | not null | plain | |
child_id | integer | not null | plain | |
level | integer | not null | plain | |
entity | text | | extended | |
和这样的行(删除了 uid 列)
parent_id | child_id | level | entity
-----------+----------+-------+--------
11 | 22 | 4 | a
22 | 33 | 5 | a
33 | 44 | 6 | a
11 | 22 | 7 | b
22 | 33 | 4 | b
33 | 44 | 5 | b
我想要一个输出,其中每行的 returns level
值基于每个 [=17= 独特的 parents 的最小值 level
].
这是我想要的输出:
parent_id | child_id | level | entity
-----------+----------+-------+--------
11 | 22 | 4 | a
22 | 33 | 4 | a
33 | 44 | 4 | a
11 | 22 | 7 | b
22 | 33 | 4 | b
33 | 44 | 4 | b
递归方法是可取的,因为层次结构深度不固定。
注:(parent_id,child_id,entity)在table
实际上parent_id和child_id是用户。 a parent 为 a child 提供实体的访问级别。然后 child 用户可以授予另一个 child 用户一定级别的访问权限。在某些时候,parent 的 parent 可能会更改访问级别,如果它是 child。现在所有更深的 children 都必须具有不超过该级别的访问权限。因为parent的parent可能会回滚更改,所以无法使用触发器来更新相应的行。
一个场景:
- 11,22,7,b 表示 user-11 将 7 的
level
给 user-22 给 b
实体。
- 现在 user-22 在某个时候将 5 的 user-33 级别提供给
b
实体
- 然后 user-33 将 5 的等级赋予 user-44
b
实体。
- 重要提示: 用户 22 将
b
的访问级别更改为 4 对于 user-33,这就是您在示例 table 中看到的
b
实体 的 user-33 到 user-44 的访问级别 应该 在 table 中保持 5
但我想要一个查询,该查询将为该列 return 4,就好像我递归地对级别超过 4 的 user-22 的所有 children 执行此操作一样。
谢谢
递归查询的初始部分查找根(没有父节点的节点),在递归部分我们简单地为实体选择一个较低的级别:
with recursive cte as (
select parent_id, child_id, level, entity
from access_level t
where not exists (
select from access_level l
where l.child_id = t.parent_id)
union all
select t.parent_id, t.child_id, least(c.level, t.level), t.entity
from cte c
join access_level t
on t.parent_id = c.child_id and t.entity = c.entity
)
select *
from cte
order by entity, parent_id
有这样的table
Table "public.access_level"
Column | Type | Modifiers | Storage | Stats target | Description
-----------+---------+-----------+----------+--------------+-------------
uid | uuid | not null | plain | |
parent_id | integer | not null | plain | |
child_id | integer | not null | plain | |
level | integer | not null | plain | |
entity | text | | extended | |
和这样的行(删除了 uid 列)
parent_id | child_id | level | entity
-----------+----------+-------+--------
11 | 22 | 4 | a
22 | 33 | 5 | a
33 | 44 | 6 | a
11 | 22 | 7 | b
22 | 33 | 4 | b
33 | 44 | 5 | b
我想要一个输出,其中每行的 returns level
值基于每个 [=17= 独特的 parents 的最小值 level
].
这是我想要的输出:
parent_id | child_id | level | entity
-----------+----------+-------+--------
11 | 22 | 4 | a
22 | 33 | 4 | a
33 | 44 | 4 | a
11 | 22 | 7 | b
22 | 33 | 4 | b
33 | 44 | 4 | b
递归方法是可取的,因为层次结构深度不固定。
注:(parent_id,child_id,entity)在table
实际上parent_id和child_id是用户。 a parent 为 a child 提供实体的访问级别。然后 child 用户可以授予另一个 child 用户一定级别的访问权限。在某些时候,parent 的 parent 可能会更改访问级别,如果它是 child。现在所有更深的 children 都必须具有不超过该级别的访问权限。因为parent的parent可能会回滚更改,所以无法使用触发器来更新相应的行。
一个场景:
- 11,22,7,b 表示 user-11 将 7 的
level
给 user-22 给b
实体。 - 现在 user-22 在某个时候将 5 的 user-33 级别提供给
b
实体 - 然后 user-33 将 5 的等级赋予 user-44
b
实体。 - 重要提示: 用户 22 将
b
的访问级别更改为 4 对于 user-33,这就是您在示例 table 中看到的
b
实体 的 user-33 到 user-44 的访问级别 应该 在 table 中保持 5
但我想要一个查询,该查询将为该列 return 4,就好像我递归地对级别超过 4 的 user-22 的所有 children 执行此操作一样。
谢谢
递归查询的初始部分查找根(没有父节点的节点),在递归部分我们简单地为实体选择一个较低的级别:
with recursive cte as (
select parent_id, child_id, level, entity
from access_level t
where not exists (
select from access_level l
where l.child_id = t.parent_id)
union all
select t.parent_id, t.child_id, least(c.level, t.level), t.entity
from cte c
join access_level t
on t.parent_id = c.child_id and t.entity = c.entity
)
select *
from cte
order by entity, parent_id