为每组分组的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

下一篇: Select From all tables