Heim > Fragen und Antworten > Hauptteil
P粉5187995572023-08-21 13:24:03
正确的解决方案是:
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
中的每一行与具有相同Group
列值和较大Age
列值的b
中的所有行进行匹配。任何o
中的行如果在Age
列中没有其组中的最大值,则会与b
中的一行或多行匹配。
LEFT JOIN
使其将组中的最年长的人(包括那些独自一人的人)与来自b
的一行NULL
进行匹配('组中没有更大的年龄')。
使用INNER JOIN
会使这些行不匹配,并且它们会被忽略。
WHERE
子句仅保留从b
中提取的字段中具有NULL
的行。它们是每个组中最年长的人。
这个解决方案和许多其他解决方案在书籍《SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming》中有详细解释。
P粉7416783852023-08-21 12:41:11
在mysql中有一种超级简单的方法可以做到这一点:
select * from (select * from mytable order by `Group`, age desc, Person) x group by `Group`
这个方法有效是因为在mysql中,你可以不对非group by列进行聚合,这种情况下mysql只返回第一行。解决方法是首先按照你想要的顺序对数据进行排序,然后按照你想要的列进行分组。
你避免了复杂的子查询尝试找到max()
等等的问题,也避免了当有多个具有相同最大值的行时返回多行的问题(其他答案会这样做)。
注意:这是一种仅适用于mysql的解决方案。我知道的所有其他数据库都会抛出一个SQL语法错误,错误信息为“非聚合列未在group by子句中列出”或类似的错误。因为这个解决方案使用了未记录的行为,更谨慎的人可能希望包含一个测试来确保它在MySQL的未来版本更改此行为时仍然有效。
自5.7版本起,sql-mode
设置默认包含ONLY_FULL_GROUP_BY
,所以要使其工作,你必须不使用此选项(编辑服务器的选项文件以删除此设置)。