我正在研究一个看起来像这样的表:
user_id | key | scope | value
--------+-------------+-----------+-------
1 | someSetting | user | false
1 | someSetting | group | true
1 | someSetting | company | false
2 | someSetting | user | false
2 | someSetting | group | true
3 | someSetting | user | false
4 | someSetting | group | true
设置采用层次结构:company -> group -> user
,用户覆盖该组,而该组又覆盖公司。当user_id
查询时,我希望通过此层次结构有效地合并设置(如果存在)。对于上面的示例,我想看到这个结果:
user_id | key | value
--------+-------------+-------
1 | someSetting | false
2 | someSetting | true
3 | someSetting | false
4 | someSetting | true
我正在从Postgres检索行之后进行合并操作,但如果可以在查询本身中完成,则会更有效。我查看了聚合函数,但看起来并不符合我的要求。
这看起来很简单,我确信可以使用Postgres完成。任何指针赞赏!
您可以使用ROW_NUMBER()
窗口功能与PARTITION BY
和非常酷的ORDER BY
。
理念:
ROW_NUMBER
和user_id
获取每个记录的ORDER BY
自定义排序顺序。SELECT
你想要的CTE a
WHERE
行号是1。例:
WITH a AS
(
SELECT user_id
, key
, scope
, ROW_NUMBER() OVER(PARTITION BY user_id
ORDER BY array_position(array['user','group','company'], scope)) AS rno
FROM test
)
SELECT user_id
, key
, scope
FROM a
WHERE rno = 1;
DBFiddle表明它的工作。
额外奖励:如果您要创建一个函数来执行此操作,您甚至可以传入其他数组来设置自定义排序顺序。
你想要做的是将范围设置从单独的行更改为单独的列,因此您的记录集看起来像这样(注意我使用0表示false,1表示true):
+---------+-------------+--------------+---------------+-----------------+ | user_id | key | user_setting | group_setting | company_setting | +---------+-------------+--------------+---------------+-----------------+ | 1 | someSetting | 0 | 1 | 0 | | 2 | someSetting | 0 | 1 | NULL | | 3 | someSetting | 0 | NULL | NULL | | 4 | someSetting | NULL | 1 | NULL | +---------+-------------+--------------+---------------+-----------------+
要做到这一点,你有几个选择。这是其中之一,使用条件聚合。基本上,你按照user_id
和key
进行分组,然后将一个聚合函数(可以是MIN
或MAX
)和CASE
语句组合在一起:
WITH settings_pivot AS ( SELECT [user_id], [key], MIN(CASE WHEN [scope] = 'user' THEN [value] ELSE NULL END) AS user_setting, MIN(CASE WHEN [scope] = 'group' THEN [value] ELSE NULL END) AS group_setting, MIN(CASE WHEN [scope] = 'company' THEN [value] ELSE NULL END) AS company_setting FROM settings GROUP BY [user_id], [key] ) SELECT [user_id], [key], COALESCE(user_setting, group_setting, company_setting) AS derived_setting FROM settings_pivot
如果您只是来自settings_pivot CTE的SELECT *
,那么您将获得我在开头的数据。但是,使用COALESCE
,您可以在指示时给出优先权。
注意:我正在使用SQL Server,因为我机器上的Postgres不想启动。所以你必须用双引号替换方括号:"user_id"
而不是[user_id]
。