使用 MIN() 和 GROUP BY [重复] 时,SQL SELECT 的行为不符合预期

Posted

技术标签:

【中文标题】使用 MIN() 和 GROUP BY [重复] 时,SQL SELECT 的行为不符合预期【英文标题】:SQL SELECT not behaving as expected when using MIN() and GROUP BY [duplicate] 【发布时间】:2021-01-29 08:57:34 【问题描述】:

我有一个简单的在线排行榜,它还将回放编码为字符串。尽管排行榜存储了(当前)报告的每个单圈时间,但检索 php 只返回每个唯一玩家的最佳时间,因此:

SELECT driver
     , MIN(time)
     , track
     , replay 
  FROM Laptimes 
 WHERE track = '$track'
 GROUP 
    BY driver 
 ORDER 
    BY MIN(time) ASC 
 LIMIT 10

这会正确报告最快的单圈时间,但不会选择与该单圈时间相关的重播。

相反,您只会收到为该驱动程序提交的第一个重播。

我 100% 确定回放正确存储在数据库中,因为如果我删除 MIN(),我会得到每个玩家的每圈时间,并且可以毫无问题地观看每个回放。

我似乎无法说服 SQL 给我与最短单圈时间相关的回放。

【问题讨论】:

这必须是旧版本的 mysql,因为任何其他 RDBMS 和任何新版本的 Mysql(5.7 或更高版本)如果不包含任何非聚合您的 group by 语句中的列。您要么需要在 select 子句中使用聚合公式聚合列,要么该列必须在 group by 子句中。否则你会得到像你看到的那样奇怪的废话结果。 【参考方案1】:

您想要整行,因此您需要过滤而不是聚合。一种简单的方法是使用相关子查询:

select l.*
from laptimes l
where
    track = ? 
    l.time = (select min(l1.time) from laptimes l1 where l1.driver = l.driver and l1.track = l.track)

请注意,正如 JNevill 所评论的,您的原始查询不是有效的标准 SQL,因为 selectgroup by 子句不一致。 MySQL 可能会容忍它(如果您禁用了选项ONLY_FULL_GROUP_BY,这是旧版本中的默认值),但是您会在group by 子句中不存在的非聚合列中获得任意值。当查询编写如下(相当于您的原始代码 - 并且是有效的 MySQL 代码)时,这可能更容易理解:

SELECT driver, MIN(time), ANY_VALUE(track), ANY_VALUE(replay) 
FROM Laptimes 
WHERE (track='$track') 
GROUP BY driver 
ORDER BY MIN(time) ASC LIMIT 10

注意 #2:使用准备好的语句!不要将参数混入查询字符串 - 这既低效又不安全。

【讨论】:

效果很好,谢谢!有趣的是,我从另一个关于排行榜的 SO 问题中得到了我正在使用的查询:/嘿嘿。

以上是关于使用 MIN() 和 GROUP BY [重复] 时,SQL SELECT 的行为不符合预期的主要内容,如果未能解决你的问题,请参考以下文章

带有 SQL MIN() 和 GROUP BY 的额外字段

关于max()/min()和group by 的坑

SQL - GROUP BY和ORDER BY MIN

不能在 Group by/Order by/Where/ON 子句中使用 Group 或 Aggregate 函数(min()、max()、sum()、count()、...等)

sql中order by和group by的区别

使用 group_by 和 summarise 时出现重复行