对分组内的行进行排名(2 列)
Posted
技术标签:
【中文标题】对分组内的行进行排名(2 列)【英文标题】:Rank rows within grouped by (2 columns) 【发布时间】:2021-03-24 06:39:54 【问题描述】:我写了一个查询来获取这样的数据(附图),user_id 和 topic_id 被分组并计算分数的平均值。我想对每个用户的分数进行排名,因此每个用户的最高 topic_id 排名为 1。我们如何编写查询来对他们的分数进行排名,因为我需要为每个用户选择第一行。
表格是这样的 -
USER_ID TOPIC_ID SCORE
------------- ------------- ------
b33e3100a7be 829e4b89c318 85
b33e3100a7be b19b6f2b2975 82
b33e3100a7be e305c970701c 81.6
b33e3100a7be 6c6fac161e65 81.6
7379ce6bc5a9 6c6fac161e65 54.6
7379ce6bc5a9 e305c970701c 54.6
7379ce6bc5a9 b19b6f2b2975 51.6
并希望输出看起来像这样。
USER_ID TOPIC_ID SCORE RANK
------------- ------------- ------ -----
b33e3100a7be 829e4b89c318 85 1
b33e3100a7be b19b6f2b2975 82 2
b33e3100a7be e305c970701c 81.6 3
b33e3100a7be 6c6fac161e65 81.6 3
7379ce6bc5a9 6c6fac161e65 54.6 1
7379ce6bc5a9 e305c970701c 54.6 1
7379ce6bc5a9 b19b6f2b2975 54.6 2
enter image description here
【问题讨论】:
【参考方案1】:您可以使用窗口函数获得所有最高分:
select t.*
from (select t.*,
rank() over (partition by user_id order by score desc) as seqnum
from t
) t
where seqnum = 1;
在这种情况下,rank()
返回所有最高的主题,如果有平局的话。 row_number()
任意返回一个。
您还可以使用相关子查询:
select t.*
from t
where t.score = (select max(t2.score)
from t t2
where t2.user_id = t.user_id
);
请注意,这两种方法都可以合并到聚合查询中。无需保存中间结果即可获得您想要的结果。
【讨论】:
【参考方案2】:您可以使用 distinct on
获得每次使用的最高分行:
select distinct on (user_id) t.*
from mytable t
order by user_id, score desc
如果您要显示您正在开始的数据,以及您用来生成所显示的中间结果集的查询,我们可能会进一步优化代码。您可能想为此提出一个新问题,提供适当的示例数据、所需结果和现有代码。
如果你想允许平局,那么你可以使用rank()
:
select *
from (
select t.*,
rank() over(partition by user_id order by score desc) rn
from mytable t
) t
where rn = 1
或者,在 Postgres 13 中:
select t.*
from mytable t
order by rank() over(partition by user_id order by score desc)
fetch first 1 row with ties
【讨论】:
我已经编辑了问题、示例表和添加到其中的输出。 但是如果用户有 2 个不同的主题,并且两者的分数相同,并且它们是该用户的前两行,我需要两行而不是一行。以上是关于对分组内的行进行排名(2 列)的主要内容,如果未能解决你的问题,请参考以下文章
我有一个带有列表的熊猫列。对包含来自同一列的至少一个公共元素的行进行分组