如何为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 表,每个用户都有一个不同的行。如果您没有,请创建它!见:

Is there a way to SELECT n ON (like DISTINCT ON, but more than one of each) Select first row in each GROUP BY group?

我们可以利用它来实现一个可更好扩展的替代查询——在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。见:

Sort by column ASC, but NULL values first?

为了将用户保留在表tbl 中没有任何行的结果中,用户LEFT JOIN LATERAL (...) ON true。见:

What is the difference between LATERAL JOIN and a subquery in PostgreSQL?

【讨论】:

【参考方案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中的每个用户返回具有最大值的类别?的主要内容,如果未能解决你的问题,请参考以下文章

如何为用户返回每月最大日期

如何为HSQL中的每个组选择列中具有最大值的行?

Postgresql:如何为postgres中的相同时间戳选择“媒体”列中的最大值?

如何为 oracle 中的每个线程选择和阻止行?(PostgreSQL 有一个工作示例)

如何为 PostgreSQL 中的自链接记录设计最佳实践数据结构?

如何为与python中列的最大值对应的多索引的每个级别返回索引