mysql - 重写 SQL 查询以修复 MySQL 5.7 严格模式导致的功能依赖问题
问题描述
我最近将我的 MySQL 服务器升级到 5.7 版,但以下示例查询不起作用:
SELECT *
FROM (SELECT *
FROM exam_results
WHERE exam_body_id = 6674
AND exam_date >= DATE_SUB(CURDATE(), INTERVAL 1 WEEK)
AND subject_ids LIKE '%4674%'
ORDER BY score DESC
) AS top_scores
GROUP BY user_id
ORDER BY percent_score DESC, time_advantage DESC
LIMIT 10
该查询应该从指定的表中选择与在某个时间间隔内完成特定考试的最高得分者匹配的考试结果。我在第一次编写查询时必须包含 GROUP BY 子句的原因是为了消除重复用户,即在同一时间段内有多个最高分的用户参加考试。在不消除重复用户 ID 的情况下,前 10 名高分者的查询可能会返回同一个人的考试结果。
我的问题是:如何重写此查询以消除与 MySQL 5.7 严格模式相关的错误,该模式在 GROUP BY 子句上强制执行,同时仍保留我想要的功能?
解决方案
当您GROUP BY
按列的子集 ( ) 聚合 ( ) 结果集时,user_id
需要聚合所有其他列。
注意:根据 SQL 标准,如果您按主键分组,则没有必要这样做,因为所有其他列都依赖于 PK。但是,您的问题并非如此。
现在,您可以使用任何聚合函数,如MAX()
、MIN()
、SUM()
等。我选择使用MAX()
,但您可以为其中任何一个更改它。
查询可以运行为:
SELECT
user_id,
max(exam_body_id),
max(exam_date),
max(subject_ids),
max(percent_score),
max(time_advantage)
FROM exam_results
WHERE exam_body_id = 6674
AND exam_date >= DATE_SUB(CURDATE(), INTERVAL 1 WEEK)
AND subject_ids LIKE '%4674%'
GROUP BY user_id
ORDER BY max(percent_score) DESC, max(time_advantage) DESC
LIMIT 10
请参阅DB Fiddle上的运行示例。
现在,您问为什么需要聚合其他列?由于您正在对行进行分组,因此引擎需要为每组生成一行。因此,当有许多值可供选择时,您需要告诉引擎选择哪个值:最大的值、最小的值、它们的平均值等。
在 MySQL 5.7.4 或更早版本中,引擎不要求您聚合其他列。引擎默默随机为你决定。您今天可能已经得到了您想要的结果,但明天引擎可能会在您不知情的情况下选择 theMIN()
而不是 the MAX()
,因此每次运行查询时都会导致不可预测的结果。
推荐阅读
- ruby - 临时自定义事件未使用 ruby sdk 登录 App 洞察
- xcode - 将 Intel fortran 编译器与 XCode IDE 集成
- python - 根据列中的 ID 组合和扩展 Dataframe
- php - 将多个可选参数传递给路由
- python - 在可滚动框架内居中和展开小部件
- javascript - 当我使用谷歌翻译切换其他语言时,购物车功能不起作用,其中使用了一些 vuejs 代码
- database - Visual Studio 2022 asp.net core 从 sql 添加模型
- php - WordPress:如何将类别页面标题更改为仅类别名称?
- json - 嵌套 JSON 数组结构的 Kafka 流创建
- jsp - OWASP CSRFGuard 不工作(404 未找到错误)