【问题标题】:MySQL query with GROUP BY behaving differently between MySQL versions?使用 GROUP BY 的 MySQL 查询在 MySQL 版本之间表现不同?
【发布时间】:2020-04-17 15:54:34
【问题描述】:

我有两个 MySQL 表 - 设备和校准,其中设备表示设备库存,校准保存每个设备校准的记录。一台设备将进行多次校准。

在 MySQL 5.5 中,以下查询完全可以识别最近校准已过期的设备:

SELECT * FROM equipment AS e
LEFT JOIN (
  SELECT calibration_id, equipment_id, calibration_company, certificate_no, date_certified, date_nextdue
  FROM (
    SELECT calibration_id, equipment_id, calibration_company, certificate_no, date_certified, date_nextdue
    FROM calibration
    WHERE deleted=0
    ORDER BY date_certified DESC
  ) AS a GROUP BY a.equipment_id
) AS c ON c.equipment_id=e.equipment_id
WHERE e.deleted=0 AND c.date_nextdue <= CURRENT_DATE()

然而,在 MySQL 5.7 中,相同的 SQL 查询有效,但返回的行包括最旧的校准而不是最新的。

我一直在尝试不同的联接,但都需要 GROUP BY 工具,而这似乎是一切都出错的地方。

虽然上面是一个虚构的示例,但我有很多查询在结构上非常相似并且行为方式相同。我的问题分为两部分:

  1. 为什么这在 MySQL 5.7 中表现不同,以及

  2. 我需要对 SQL 进行哪些更改才能使其在 MySQL 5.7 中按预期运行?

感谢您的帮助。

【问题讨论】:

  • SELECT 中有列,GROUP BY 中没有。您的查询是 - 并且一直是 - 坏了。我建议您再问一个问题,并提供示例数据、所需结果和逻辑解释,以便您学习如何编写正确的查询来做您想做的事情。
  • 你应该阅读手册中的函数依赖。
  • 获取一些数据并在启用了 only_full_group 的 dbfiddle 中测试您的查询,在那里您可以看到为什么您的查询不正常。

标签: mysql sql join group-by


【解决方案1】:

您的原始查询在不属于group by 子句的select 子句中有非聚合列。虽然 MySQL 可能允许这样做,但实际上将选择哪个值是未定义的,这意味着它不能保证在连续执行中保持一致。

防止开发者掉入这个陷阱是 MySQL 从 5.7 开始默认启用ONLY_FULL_GROUP_BY 的原因之一(由于您的查询仍在运行,这意味着在您的新数据库的配置中明确禁用了此 sql 模式服务器)。

如果我正确理解了您的查询,您可以改用相关子查询:

select e.*
from equipments e
where (
    select max(c.date_certified) 
    from calibration c 
    where c.equipment_id = e.equipment_id and c.deleted = 0
) <= current_date

【讨论】:

  • 感谢您,我实际上已经尝试过相关子查询方法,但到目前为止还无法获得我需要的所有列。我所追求的伪代码版本将是这样的:获取所有设备的列表(所有列,不包括已删除的设备),在同一行上,该设备最近校准记录的列,并且所有结果按下一次校准的截止日期降序排列。任何没有事先校准的设备仍应出现在列表中,但校准列的值为 NULL。谢谢
  • @richhallstoke:如果您可以提供某种形式的db<>fiddle 以及您的样本数据和预期结果,将会有所帮助。
  • 我很想但不知道如何使用 dbfiddle。无论我输入什么,我都会遇到运行失败的错误:(
  • 如果我在 GROUP BY 语句中包含所有列,它不会过滤,因此我每台设备只有一次校准。正常工作时,我应该只有 3 行 eqt 1 & cal 2、eqt 2 & cal 4、eqt 3 & cal 6 - db-fiddle.com/f/bEuUi76eJ5LjCwkTgzmAwU/0
猜你喜欢
  • 2016-08-28
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 2017-11-14
  • 1970-01-01
  • 2011-11-11
相关资源
最近更新 更多