SQL 需要查询帮助:如何在同一个 table 中排除或优先处理 SQL 中的行

SQL query help needed: How to exclude or prioritize rows in SQL in the same table

我有问题

我有一个包含用户、角色、客户端和系统的应用程序。 我有一个名为 'policies' 的 table,其中包含我的应用程序所依赖的 22 policies/rules。 22 个中的每一个都可以在一个或多个级别上定义。 级别可以是:系统、客户端、角色或用户。 一个系统有 N 个客户端,一个客户端有 N 个角色,一个角色有 N 个用户。 默认情况下,所有 22 个策略都是在系统级别定义的,但它们可以在任何较低级别被覆盖。

请参阅下面的 table 示例。为系统定义了 22 个策略 (system_id)。请注意 policy_1 也是如何在客户端、角色和用户级别设置的(具有相应的 ID)。


            name             |  value   |                level                 
-----------------------------+----------+--------------------------------------
policy_1                     |    1     |                 system_id
policy_2                     |    4     |                 system_id
policy_3                     |    6     |                 system_id

[policies 4 to 21]           |   ...    |                    ...

policy_22                    |    9     |                 role_id
policy_1                     |    2     |                 client_id
policy_1                     |    9     |                 role_id
policy_1                     |    7     |                 user_id
(22 rows)

即使 policy_1 是在系统级别设置的,但在客户端级别进行设置时,策略的值才是最重要的。在角色级别和用户级别设置时再次发生同样的情况。

查询输入

查询输出 22 项政策设置在最低级别。也就是说,策略应按其设置的最低级别排列优先级。

我尝试过的东西

嗯嗯。 . .如果我理解正确,你可以使用 distinct on。关键是过滤和排序:

select distinct on (name) p.*
from policies p
where level = 'system_id' and value = $system_id or
      level = 'client_id' and value = $client_id or
      level = 'role_id' and value = $role_id or
      level = 'user_id' and value = $user_id
order by p.name,
         (case when level when 'system_id' then 1 when 'client_id' then 2 when 'role_id' then 3 when 'user_id' then 4 end) desc
      

感谢Gordon Linoff的回答,我可以按照他的策略找到一个很好的解决方案(distinct on + order by + case)。这可能不是最优雅或最有效的,但它确实有效。让我知道是否可以进一步改进。

select distinct on (name) *
from policies
where level = $system_id  or
      level = $client_id or
      level = $role_id  or
      level = $user_id
order by name,
         (case when level = $system_id then 1 when level = $client_id then 2 when level = $role_id then 3 when level = $user_id then 4 end) desc;