为每组分组的SQL结果获取最大值的记录
你如何获得包含每个分组集合的最大值的行?
我在这个问题上看到了一些过于复杂的变体,没有一个答案很好。 我试图把最简单的例子放在一起:
给出如下的表格,包括人员,组别和年龄栏,你如何得到每个组中最年长的人? (组内联系应该给出第一个按字母顺序排列的结果)
Person | Group | Age
---
Bob | 1 | 32
Jill | 1 | 34
Shawn| 1 | 42
Jake | 2 | 29
Paul | 2 | 36
Laura| 2 | 39
预期结果集:
Shawn | 1 | 42
Laura | 2 | 39
在mysql中有这样一个超级简单的方法:
select *
from (select * from mytable order by `Group`, age desc, Person) x
group by `Group`
这是可行的,因为在mysql中你可以不聚合非分组列,在这种情况下,mysql只返回第一行。 解决方案是首先对数据进行排序,以便为每个组选择您想要的行,然后按您想要的值进行分组。
你避免了复杂的子查询,它们试图找到max()
等等,还有当有多个具有相同最大值的多行时返回多行的问题(和其他答案一样)
注意:这是一个仅限于mysql的解决方案。 我所知道的所有其他数据库都会在消息“非聚合列未列在group by子句中”或类似消息中引发SQL语法错误。 由于此解决方案使用未记录的行为,因此更谨慎的方法可能需要包含一个测试来声明在未来版本的MySQL更改此行为时它仍然可以正常工作。
版本5.7更新:
自5.7版以来,默认情况下, sql-mode
设置包括ONLY_FULL_GROUP_BY
,所以为了使其工作,您不能使用此选项(编辑服务器的选项文件以删除此设置)。
正确的解决方案是:
SELECT o.*
FROM `Persons` o # 'o' from 'oldest person in group'
LEFT JOIN `Persons` b # 'b' from 'bigger age'
ON o.Group = b.Group AND o.Age < b.Age
WHERE b.Age is NULL # bigger age not found
怎么运行的:
它将来自o
每一行与来自b
所有行在列Group
具有相同的值并且在列Age
具有较大的值相匹配。 从任意行o
不具有其在列组的最大值Age
将匹配从一个或多个行b
。
LEFT JOIN
使它与来自b
('没有最大年龄的组')中的满足NULL
的行匹配组中最老的人(包括在他们组中单独的人)。
使用INNER JOIN
使这些行不匹配,它们被忽略。
WHERE
子句只保留从b
提取的字段中具有NULL
s的行。 他们是每个组别中年龄最大的人。
更多的读物
SQL解决方案:避免数据库编程的陷阱“一书中解释了这个解决方案和许多其他解决方案
我简单的SQLite解决方案(可能是MySQL):
SELECT *, MAX(age) FROM mytable GROUP BY `Group`;
但是它在PostgreSQL和其他平台上不起作用。
在PostgreSQL中,您可以使用DISTINCT ON子句:
SELECT DISTINCT ON ("group") * FROM "mytable" ORDER BY "group", "age" DESC;
链接地址: http://www.djcxy.com/p/94331.html
上一篇: Get records with max value for each group of grouped SQL results