下面是一个最简单的例子,尽管任何解决方案都应该能够扩展到需要多少n个top结果:
如果有一个这样的表格,有person、group和age列,那么如何得到每组中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 |
+--------+-------+-----+
注意:这个问题建立在前一个问题的基础上——获取每组分组sql结果的最大值记录——从每个组中获取一个顶行,并从@bohemian得到了一个很好的mysql特定答案:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
我很想以此为基础,尽管我不知道怎么做。
11条答案
按热度按时间eqzww0vc1#
参考leetcode
q9yhzks02#
snuffin解决方案在有大量行的情况下执行起来似乎相当慢,而且mark byers/rick james和bluefeet解决方案在我的环境(mysql 5.6)上不起作用,因为order by是在执行select之后应用的,所以下面是marc byers/rick james解决方案的一个变体来解决这个问题(使用一个额外的重叠select):
我在一个有500万行的表上尝试了类似的查询,结果在3秒内返回
z5btuh9x3#
看看这个:
sql小提琴:http://sqlfiddle.com/#!2015年6月2日
h6my8fg24#
试试这个:
演示
1l5u6lss5#
在其他数据库中,可以使用
ROW_NUMBER
. mysql不支持ROW_NUMBER
但您可以使用变量来模拟它:在线查看:sqlfiddle
编辑我刚刚注意到蓝脚报给他一个非常相似的答案:+1。然而,这个答案有两个小优点:
这是一个单一的查询。变量在select语句中初始化。
它处理问题中描述的关系(按名称的字母顺序)。
所以我把它放在这里,以防它能帮助别人。
fsi0uk1n6#
在sql server中
row_numer()
是一个强大的函数,可以很容易地得到如下结果lyr7nygr7#
如果其他答案不够快,请尝试以下代码:
输出:
q7solyqu8#
如何使用自连接:
给了我:
比尔·卡尔温的回答给了我很大的启发,他为每个类别选出了十大唱片
另外,我正在使用sqlite,但这应该可以在mysql上使用。
另一件事:在上面,我替换了
group
带有groupname
为方便起见。编辑:
根据op关于缺少平局结果的评论,我增加了snuffin的答案来显示所有的平局。这意味着如果最后一行是ties,则可以返回2行以上的数据,如下所示:
给了我:
2uluyalo9#
在mysql中,有一个非常好的答案来解决这个问题——如何获得每组前n行
根据引用链接中的解决方案,您的查询如下:
哪里
n
是top n
以及your_table
表的名称。我认为参考文献中的解释非常清楚。为了快速参考,我将复制并粘贴到这里:
目前mysql不支持row_number()函数,该函数可以在一个组中分配一个序列号,但是作为一种解决方法,我们可以使用mysql会话变量。
这些变量不需要声明,可以在查询中用于进行计算和存储中间结果。
@current\u country:=country此代码对每行执行,并将country列的值存储到@current\u country变量。
@country\u rank:=if(@current\u country=country,@country\u rank+1,1)在本代码中,如果@current\u country是相同的我们递增rank,否则设置为1。对于第一行,@current\u country为空,因此rank也设置为1。
为了获得正确的排名,我们需要按国家、人口、人口和性别排序
pprl5pva10#
这里有一种方法,使用
UNION ALL
(参见SQLFiddle演示)。这适用于两个组,如果有两个以上的组,则需要指定group
为每个查询编号并添加查询group
:有多种方法可以做到这一点,请参阅本文以确定适合您的情况的最佳路线:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
编辑:
这可能也适用于您,它为每条记录生成一个行号。使用上面链接中的示例,这将仅返回行号小于或等于2的记录:
请参见演示
7qhs6swi11#
我想和大家分享这一点,因为我花了很长时间寻找一种简单的方法来在我正在开发的java程序中实现这一点。这并不能给出你想要的结果,但已经很接近了。mysql中的函数
GROUP_CONCAT()
在指定每组返回多少个结果方面效果非常好。使用LIMIT
或者其他任何一种奇特的方法COUNT
不适合我。因此,如果您愿意接受修改后的输出,这是一个很好的解决方案。假设我有一个名为“学生”的表格,上面有学生ID、性别和平均绩点。假设我希望每个性别的平均绩点达到前5名。然后我可以这样写查询请注意,参数“5”告诉它每行要连接多少个条目
输出结果看起来像
您还可以更改
ORDER BY
变量并以不同的方式排序。因此,如果我有学生的年龄,我可以取代'平均绩点下降'与'年龄下降',这将工作!还可以向GROUPBY语句中添加变量,以在输出中获得更多的列。所以这是我发现的一种非常灵活的方法,如果你对列出的结果满意的话,它会很好的工作。