如何为postgresql中的每个用户返回具有最大值的类别?
Posted
技术标签:
【中文标题】如何为postgresql中的每个用户返回具有最大值的类别?【英文标题】:How to return the category with max value for every user in postgresql? 【发布时间】:2021-11-11 01:44:52 【问题描述】:这是桌子
id | category | value |
---|---|---|
1 | A | 40 |
1 | B | 20 |
1 | C | 10 |
2 | A | 4 |
2 | B | 7 |
2 | C | 7 |
3 | A | 32 |
3 | B | 21 |
3 | C | 2 |
我想要这样的结果
id | category |
---|---|
1 | A |
2 | B |
2 | C |
3 | A |
【问题讨论】:
你可以参考一些主题SELECT value WITH MAX...
,e.g
【参考方案1】:
对于小表或每个用户只有很少行,使用窗口函数rank()
(如demonstrated by The Impaler)的子查询就可以了。对整个表进行顺序扫描,然后进行排序将是最有效的查询计划。
但对于每个用户多于几行,这会变得越来越低效。
通常,您还有一个users
表,每个用户都有一个不同的行。如果您没有,请创建它!见:
我们可以利用它来实现一个可更好扩展的替代查询——在LATERAL JOIN
中使用WITH TIES
。需要 Postgres 13 或更高版本。
SELECT u.id, t.*
FROM users u
CROSS JOIN LATERAL (
SELECT t.category
FROM tbl t
WHERE t.id = u.id
ORDER BY t.value DESC
FETCH FIRST 1 ROWS WITH TIES -- !
) t;
db小提琴here
见:
Get top row(s) with highest value, with ties Fetching a minimum of N rows, plus all peers of the last row这可以使用多列 index 来达到很好的效果 - 当然必须存在:
CREATE INDEX ON tbl (id, value);
或者:
CREATE INDEX ON tbl (id, value DESC);
更快的index-only scans 成为可能:
CREATE INDEX ON tbl (id, value DESC, category);
或(当前查询的最佳值):
CREATE INDEX ON tbl (id, value DESC) INCLUDE (category);
假设value
定义为NOT NULL
,或者我们必须使用DESC NULLS LAST
。见:
为了将用户保留在表tbl
中没有任何行的结果中,用户LEFT JOIN LATERAL (...) ON true
。见:
【讨论】:
【参考方案2】:您可以使用RANK()
来识别您想要的行。然后,过滤很容易。例如:
select *
from (
select *,
rank() over(partition by id order by value desc) as rk
from t
) x
where rk = 1
结果:
id category value rk
--- --------- ------ --
1 A 40 1
2 B 7 1
2 C 7 1
3 A 32 1
请参阅DB Fiddle 的运行示例。
【讨论】:
我得到“有序集聚合排名需要WITHIN GROUP”结果 @Erik 效果很好,请参阅示例。你确定你使用的是 PostgreSQL 吗?WITHIN GROUP
是一个通常可以在 Oracle 或 DB2 中找到的子句。
对不起,这是我的错,您的代码正在运行,感谢分享以上是关于如何为postgresql中的每个用户返回具有最大值的类别?的主要内容,如果未能解决你的问题,请参考以下文章
Postgresql:如何为postgres中的相同时间戳选择“媒体”列中的最大值?
如何为 oracle 中的每个线程选择和阻止行?(PostgreSQL 有一个工作示例)