使用 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,因为 select
和 group 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 的行为不符合预期的主要内容,如果未能解决你的问题,请参考以下文章
不能在 Group by/Order by/Where/ON 子句中使用 Group 或 Aggregate 函数(min()、max()、sum()、count()、...等)