【问题标题】:Postgresql select column with minimum value of hierarchical parentsPostgresql选择具有最小层次父级值的列
【发布时间】:2019-12-18 07:46:15
【问题描述】:

有这样一张桌子

                       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

我想要一个输出,它根据每个entity 特有的父母level 的最小值为每一行返回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) 在表中是唯一的

其实 parent_id 和 child_id 是用户。父级为子级授予实体的访问级别。然后,子用户可以为其自己的另一个子用户提供一定级别的访问权限。在某些时候,父母的父母可能会更改其孩子的访问级别。现在所有更深的孩子都必须拥有不超过此的访问级别。无法使用触发器来更新相应的行,因为 parent of parent 可能会回滚更改。

一个场景:

  • 11,22,7,b 表示用户 11 将 level 的 7 分配给 b 实体。
  • 现在 user-22 在某个时候将 5 的 user-33 级别赋予 b 实体
  • 然后 user-33 将 user-44 的级别 5 赋予b 实体。
  • 重要提示: user-22 将 user-33 的 b 访问级别更改为 4您在示例表中看到
  • b 实体的 user-33 对 user-44 的访问级别应该在表中保持 5

但我想要一个查询,该查询将为该列返回 4,就好像我对 user-22 的所有级别超过 4 的子级递归地执行它一样。

谢谢

【问题讨论】:

  • 听起来你想要的是一个分区:min(level) over (partition by parent_id)。您可以通过将更多列添加到分区中,将其视为group by
  • @Viorel,这是无法通过分区实现的。认为每个实体都有一棵树,对于树的每个节点,我想返回最小的 level 遍历树到根
  • 该级别列使它看起来已经是递归查询的结果,您可以按实体进行分区。数据和所需输出之间的联系对我来说不是很清楚,为什么实体 b 的父级 33 最终的级别为 4,而实体 b 的父级 11 的级别为 7?
  • @Viorel,用更多解释更新了我的答案。

标签: sql postgresql postgresql-11


【解决方案1】:

递归查询的初始部分查找根(没有父节点的节点),在递归部分我们只需为实体选择一个较少的级别:

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

Db<>fiddle.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-06
    • 2012-07-14
    • 2015-08-27
    • 1970-01-01
    • 1970-01-01
    • 2020-01-21
    • 2021-02-06
    • 1970-01-01
    相关资源
    最近更新 更多