如何有条件地为每个用户选择一行?

Posted

技术标签:

【中文标题】如何有条件地为每个用户选择一行?【英文标题】:How to select one row per user conditionally? 【发布时间】:2021-04-17 09:26:37 【问题描述】:

我有以下疑问:

select count(1) num, business_id, user_id FROM `pos_transactions` 
group by user_id, business_id
order by user_id

它返回这个:

+--------+-------------+---------+
|  num   | business_id | user_id |
+--------+-------------+---------+
| 3      | 503         | 12      |
| 7      | 33          | 12      |
| 1      | 771         | 13      |
| 2      | 86          | 13      |
| 1      | 772         | 13      |
| 4      | 652         | 14      |
| 4      | 567         | 14      |
+--------+-------------+---------+

我只需要为每个user_id 选择一行,即num 值更大的那一行。如果用户的所有num 值都相同,则应随机选择其中一个(即用户#14)。所以,这是预期的结果:

+--------+-------------+---------+
|  num   | business_id | user_id |
+--------+-------------+---------+
| 7      | 33          | 12      |
| 2      | 86          | 13      |
| 4      | 567         | 14      |
+--------+-------------+---------+

知道我该怎么做吗?


我想解决方案将与每个用户的limit 1 有关。但我不知道应该如何编写查询。

我想要做的就是让每个user_id 的表唯一,并且逻辑是选择具有更大num 的行。

【问题讨论】:

见meta.***.com/questions/333952/… @Strawberry 真的吗?我的问题还不够清楚? 你的mysql是什么版本的? @forpas Server version: 8.0.20 - MySQL Community Server - GPL 【参考方案1】:

使用MAX()FIRST_VALUE() 窗口函数:

SELECT DISTINCT 
       MAX(COUNT(*)) OVER (PARTITION BY user_id) num, 
       FIRST_VALUE(business_id) OVER (PARTITION BY user_id ORDER BY COUNT(*) DESC) business_id, 
       user_id 
FROM pos_transactions 
GROUP BY user_id, business_id
ORDER BY user_id

【讨论】:

太好了..感谢您的回答..只是出于好奇,如果您也分享旧的mysql版本解决方案,我将不胜感激.. @stack 我什至不会尝试没有窗口函数的解决方案。这将涉及子查询和使用在 MySql 8.0+ 中已弃用的内联变量。 好的,无论如何,谢谢.. 你知道,问题是你的查询看起来很重,对于我在现实中拥有的巨大数据集来说是不可执行的。 i.stack.imgur.com/RAnBd.png @stack 我试图在我之前的评论中描述没有窗口函数你会得到什么类型的解决方案。根据您的要求使用窗口函数的解决方案肯定比没有窗口函数的任何其他解决方案执行得更好。对于大型数据集,可以通过添加索引来提高性能。我假设 user_id 已编入索引。还有一个关于 user_id、business_id 的索引可能会有所帮助。 @stack 不,PARTITION 是 OVER() 中用于窗口函数的语法的一部分。例如 PARTITION BY user_id 表示行按 user_id 分组。

以上是关于如何有条件地为每个用户选择一行?的主要内容,如果未能解决你的问题,请参考以下文章

如何有条件地为呼叫添加资源

.Net Core MVC 路由:有条件地为每个控制器设置 MapSpaFallbackRoute

有条件地为活动/非活动用户呈现徽章

如何有条件地为 Catalyst 编译代码?

有效地为一个非常大的表中的每个组选择最新行?

有效地为集合中的每个类别选择顶行