获取每组分组结果的前n条记录
以下是最简单的示例,尽管任何解决方案都应该能够扩展到所需的 n 个顶级结果:
给定一个如下表,其中包含人员、组和年龄列,您如何获得 2每组中最年长的人?(组内的平局不应产生更多结果,而是按字母顺序给出前 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 | +--------+-------+-----+
注意:此问题建立在上一个问题的基础上 - <一href="https://stackoverflow.com/q/12102200/165673">获取每组分组 SQL 结果的最大值记录 - 用于从每个组中获取单个顶行,并且收到了很好的结果@Bohemian 的 MySQL 特定答案:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
希望能够以此为基础,尽管我不知道如何实现。
The following is the simplest possible example, though any solution should be able to scale to however many n top results are needed:
Given a table like that below, with person, group, and age columns, how would you get the 2 oldest people in each group? (Ties within groups should not yield more results, but give the first 2 in alphabetical order)
+--------+-------+-----+ | Person | Group | Age | +--------+-------+-----+ | Bob | 1 | 32 | | Jill | 1 | 34 | | Shawn | 1 | 42 | | Jake | 2 | 29 | | Paul | 2 | 36 | | Laura | 2 | 39 | +--------+-------+-----+
Desired result set:
+--------+-------+-----+ | Shawn | 1 | 42 | | Jill | 1 | 34 | | Laura | 2 | 39 | | Paul | 2 | 36 | +--------+-------+-----+
NOTE: This question builds on a previous one- Get records with max value for each group of grouped SQL results - for getting a single top row from each group, and which received a great MySQL-specific answer from @Bohemian:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
Would love to be able to build off this, though I don't see how.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
这是一种方法,使用
UNION ALL
(请参阅 SQL Fiddle with演示)。这适用于两个组,如果您有两个以上的组,则需要指定组
编号并为每个组
添加查询:有多种方法为此,请参阅本文以确定适合您情况的最佳路线:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
编辑:
这可能也适合您,它为每条记录生成一个行号。使用上面链接中的示例,这将仅返回行数小于或等于 2 的记录:
请参阅演示
Here is one way to do this, using
UNION ALL
(See SQL Fiddle with Demo). This works with two groups, if you have more than two groups, then you would need to specify thegroup
number and add queries for eachgroup
:There are a variety of ways to do this, see this article to determine the best route for your situation:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
Edit:
This might work for you too, it generates a row number for each record. Using an example from the link above this will return only those records with a row number of less than or equal to 2:
See Demo
在其他数据库中,您可以使用
ROW_NUMBER
执行此操作。 MySQL 不支持ROW_NUMBER
,但您可以使用变量来模拟它:查看它在线工作:sqlfiddle
编辑 我刚刚注意到 bluefeet 发布了一个非常相似的答案:+1 给他。然而,这个答案有两个小优点:
所以我会把它留在这里,以防它可以帮助别人。
In other databases you can do this using
ROW_NUMBER
. MySQL doesn't supportROW_NUMBER
but you can use variables to emulate it:See it working online: sqlfiddle
Edit I just noticed that bluefeet posted a very similar answer: +1 to him. However this answer has two small advantages:
So I'll leave it here in case it can help someone.
试试这个:
演示
Try this:
DEMO
使用自连接怎么样:
给我:
我受到 Bill Karwin 的回答的强烈启发 为每个类别选择前 10 条记录
另外,我正在使用 SQLite,但这应该适用于 MySQL。
另一件事:在上面,为了方便起见,我用
groupname
列替换了group
列。编辑:
根据OP关于缺少平局结果的评论,我增加了snuffin的答案以显示所有平局。这意味着如果最后一个是平局,则可以返回多于 2 行,如下所示:
给我:
How about using self-joining:
gives me:
I was strongly inspired by the answer from Bill Karwin to Select top 10 records for each category
Also, I'm using SQLite, but this should work on MySQL.
Another thing: in the above, I replaced the
group
column with agroupname
column for convenience.Edit:
Following-up on the OP's comment regarding missing tie results, I incremented on snuffin's answer to show all the ties. This means that if the last ones are ties, more than 2 rows can be returned, as shown below:
gives me:
当您有大量行并且 Mark Byers/Rick James 和 Bluefeet 解决方案在我的环境(MySQL 5.6)上不起作用时,Snuffin 解决方案执行起来似乎相当慢,因为 order by 是在执行 select 后应用的,所以这里是一个变体Marc Byers/Rick James 解决此问题的解决方案(使用额外的叠瓦式选择):
我在具有 500 万行的表上尝试了类似的查询,它在不到 3 秒的时间内返回结果
Snuffin solution seems quite slow to execute when you've got plenty of rows and Mark Byers/Rick James and Bluefeet solutions doesn't work on my environnement (MySQL 5.6) because order by is applied after execution of select, so here is a variant of Marc Byers/Rick James solutions to fix this issue (with an extra imbricated select):
I tried similar query on a table having 5 millions rows and it returns result in less than 3 seconds
如果其他答案不够快,请尝试 此代码:
输出:
If the other answers are not fast enough Give this code a try:
Output:
看看这个:
SQL Fiddle:http://sqlfiddle.com/#!2/cdbb6/15< /a>
Check this out:
SQL Fiddle: http://sqlfiddle.com/#!2/cdbb6/15
上面的查询将返回每个导演的最新 n 部电影。
Above query will returns latest n movies for each directors.
我想分享这个,因为我花了很长时间寻找一种简单的方法来在我正在开发的 java 程序中实现这个。这并不能完全给出您正在寻找的输出,但它很接近。 mysql 中名为 GROUP_CONCAT() 的函数非常适合指定每个组中返回多少结果。使用
LIMIT
或任何其他尝试使用COUNT
执行此操作的奇特方法对我来说不起作用。因此,如果您愿意接受修改后的输出,那么这是一个很好的解决方案。假设我有一个名为“学生”的表,其中包含学生 ID、性别和 GPA。假设我希望每个性别的 gpa 都达到前 5 名。然后我可以像这样编写查询请注意,参数“5”告诉它每行要连接多少个条目
输出看起来像这样
您还可以更改
ORDER BY
变量并对它们进行排序另一种方式。因此,如果我有学生的年龄,我可以将“gpa desc”替换为“age desc”,这样就可以了!您还可以向 group by 语句添加变量以在输出中获取更多列。所以这只是我发现的一种非常灵活的方法,如果您只列出结果就可以的话,效果很好。I wanted to share this because I spent a long time searching for an easy way to implement this in a java program I'm working on. This doesn't quite give the output you're looking for but its close. The function in mysql called
GROUP_CONCAT()
worked really well for specifying how many results to return in each group. UsingLIMIT
or any of the other fancy ways of trying to do this withCOUNT
didn't work for me. So if you're willing to accept a modified output, its a great solution. Lets say I have a table called 'student' with student ids, their gender, and gpa. Lets say I want to top 5 gpas for each gender. Then I can write the query like thisNote that the parameter '5' tells it how many entries to concatenate into each row
And the output would look something like
You can also change the
ORDER BY
variable and order them a different way. So if I had the student's age I could replace the 'gpa desc' with 'age desc' and it will work! You can also add variables to the group by statement to get more columns in the output. So this is just a way I found that is pretty flexible and works good if you are ok with just listing results.在SQL Server中,
row_number()
是一个强大的函数,可以轻松获得结果,如下所示In SQL Server
row_number()
is a powerful function that can get result easily as below对于这个问题有一个非常好的答案 MySQL - How To Get Top N Rows per Each组
根据引用链接中的解决方案,您的查询将类似于:
其中
n
是top n
,your_table
是您的表的名称。我认为参考文献中的解释非常清楚。为了快速参考,我将其复制并粘贴到此处:
There is a really nice answer to this problem at MySQL - How To Get Top N Rows per Each Group
Based on the solution in the referenced link, your query would be like:
where
n
is thetop n
andyour_table
is the name of your table.I think the explanation in the reference is really clear. For quick reference I will copy and paste it here:
参考leetcode
reference leetcode