以下是最简单的可能示例,但任何解决方案都应该能够扩展到需要的n个顶级结果:
给出如下表格,包含人,组和年龄列,你将如何 get the 2 oldest people in each group? (组内的关系不应该产生更多结果,但按字母顺序给出前2个)
+--------+-------+-----+
| Person | Group | Age |
+--------+-------+-----+
| Bob | 1 | 32 |
| Jill | 1 | 34 |
| Shawn | 1 | 42 |
| Jake | 2 | 29 |
| Paul | 2 | 36 |
| Laura | 2 | 39 |
+--------+-------+-----+
期望的结果集:
+--------+-------+-----+
| Shawn | 1 | 42 |
| Jill | 1 | 34 |
| Laura | 2 | 39 |
| Paul | 2 | 36 |
+--------+-------+-----+
NOTE: 这个问题 Build 在前一个Get records with max value for each group of grouped SQL results的基础上 - 从每个组中获得一个顶行,并且从@Bohemian获得了一个特定的MySQL特定答案:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
我希望能够 Build 起来,但我不知道如何 .
10 回答
在其他数据库中,您可以使用
ROW_NUMBER
执行此操作 . MySQL不支持ROW_NUMBER
,但您可以使用变量来模拟它:看到它在线工作:sqlfiddle
Edit 我刚注意到bluefeet发布了一个非常相似的答案:1给他 . 然而,这个答案有两个小优点:
这是一个单一的查询 . 变量在SELECT语句中初始化 .
它处理问题中描述的关系(按名称的字母顺序) .
所以我会留在这里,以防它可以帮助别人 .
如果其他答案不够快,请试试this code:
输出:
当你有大量行并且Mark Byers / Rick James和Bluefeet解决方案不适用于我的环境(MySQL 5.6)时,Snuffin解决方案似乎执行起来很慢,因为在执行select之后会应用order by,所以这里有一个变体Marc Byers / Rick James解决方案来解决这个问题(带有额外的叠加选择):
我在一个有5百万行的表上尝试了类似的查询,它在不到3秒的时间内返回结果
试试这个:
DEMO
看一下这个:
SQL小提琴:http://sqlfiddle.com/#!2/cdbb6/15
在SQL Server中
row_numer()
是一个功能强大的函数,可以轻松获得结果,如下所示这是一种方法,使用
UNION ALL
(参见SQL Fiddle with Demo) . 这适用于两个组,如果您有两个以上的组,那么您需要指定group
数并为每个group
添加查询:有多种方法可以执行此操作,请参阅此文章以确定适合您情况的最佳路径:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
编辑:
这也可能对您有用,它会为每条记录生成一个行号 . 使用上面链接中的示例,这将仅返回行数小于或等于2的记录:
见Demo
如何使用自加入:
给我:
Bill Karwin的回答给了我很大的启发Select top 10 records for each category
另外,我正在使用SQLite,但这应该适用于MySQL .
另一件事:在上面,为方便起见,我用
groupname
列替换了group
列 .Edit :
关于OP关于缺失领带结果的评论的后续跟进,我在snuffin的回答中增加了显示所有关系 . 这意味着如果最后一个是tie,则可以返回超过2行,如下所示:
给我:
在MySQL - How To Get Top N Rows per Each Group有一个非常好的答案来解决这个问题
根据引用链接中的解决方案,您的查询将如下所示:
其中
n
是top n
,your_table
是表的名称 .我认为参考文献中的解释非常明确 . 为了快速参考,我将在此处复制并粘贴它:
我想分享这个,因为我花了很长时间在java程序中寻找一种简单的方法来实现这一点我很好地提供了你正在寻找的输出但它的结果 . mysql中的函数
GROUP_CONCAT()
非常适合指定每组返回多少结果 . 使用LIMIT
或任何其他尝试使用COUNT
并且愿意接受修改输出的花哨方式,这是一个很好的解决方案 . 假设我有一张名为'student'的表,其中包含学生ID,性别和gpa . 让我们说我想为每个性别排名前5加帕斯 . 然后我可以像这样编写查询请注意,参数“5”表示要连接到每行的条目数
输出看起来像
您也可以更改
ORDER BY
变量并以不同的方式对它们进行排序 . 所以,如果我有学生's age I could replace the ' gpa desc ' with ' age desc',那就行了!您还可以将变量添加到group by语句以在输出中获取更多列 . 所以这只是我发现的一种非常灵活的方式,如果你只是列出结果就可以了 .