问题描述
我遇到的问题
我有一个包含用户、角色、客户端和系统的应用程序。 我有一个名为“policies”的表,其中包含我的应用程序所依赖的 22 个策略/规则。 22 个中的每一个都可以定义为一个或多个级别。 级别可以是:系统、客户端、角色或用户。 一个系统有 N 个客户端,一个客户端有 N 个角色,一个角色有 N 个用户。 默认情况下,所有 22 个策略都是在系统级别定义的,但它们可以在任何较低级别被覆盖。
请参阅下表作为示例。系统定义了 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 是在系统级别设置的,但在客户端级别设置时,这也是重要的策略值。在角色级别和用户级别设置时再次发生同样的情况。
查询输入
- system_id、client_id、role_id、user_id
查询输出 22 个策略设置在最低级别。也就是说,策略应该在它们设置的最低级别上进行优先级排序。
我尝试过的事情
- LEFTJOIN 与 NOT INTO 子句的组合
解决方法
嗯嗯。 . .如果我理解正确,您可以使用 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;