【问题标题】:MYSQL max() and group by error:only_full_group_byMYSQL max() 并按错误分组:only_full_group_by
【发布时间】:2019-04-15 13:42:42
【问题描述】:

我对自更新 MySQL-5.7 以来记录错误的 MySQL 查询有疑问。 错误是“only_full_group_by”,它将在stackoverflow上说出来。

在许多答案中都声明不要禁用此选项,而是改进您的 sql 查询。

我正在使用的查询是每小时返回一个计数器的最小值和最大值。

SELECT MAX( counter ) AS max, 
       MIN( counter ) AS min, 
       DATE_FORMAT(date_time, '%H:%i') AS dt 
FROM table1 
WHERE date_time >= NOW() - INTERVAL 1 DAY 
GROUP BY YEAR(date_time), MONTH(date_time), DAY(date_time), HOUR(date_time)

据我从错误消息中了解到,我在 GROUP BY 原因中缺少 SELECT 原因中的一项。但是,但是我恢复/删除/添加项目我没有得到升级到 MySQL-5.7 之前的结果。

我尝试对主查询进行子查询以改进 SQL 查询。但不知何故,我无法重新创建结果。

我错过了什么?

【问题讨论】:

  • DATE_FORMAT(date_time, '%H:%i') 将是不确定的,因为您只分组到 hour 级别;因此它可以返回该小时内的任何一分钟,因此会出现错误。
  • 我尝试删除“分钟”部分 (%i),但随后我完全失去了数据集的真实顺序。结果显示从 00 到 23 的时间顺序,但结果应按实际 date_time 排序并从现在开始(例如 20:00),例如:20、21、22、23、00 .... 19, 20
  • 你能设置一个db-fiddle.com

标签: mysql group-by max min


【解决方案1】:
SELECT MAX( counter ) AS max, 
       MIN( counter ) AS min,
       YEAR(date_time) AS g_year,
       MONTH(date_time)AS g_month,
       DAY(date_time) AS g_day,
       HOUR(date_time) AS g_hour 
FROM table1 
WHERE date_time >= NOW() - INTERVAL 1 DAY 
GROUP BY g_year, g_month, g_day, g_hour

或者你可以摆脱冗余数据,如果你总是这样做 1 天:

SELECT MAX( counter ) AS max, 
       MIN( counter ) AS min,
       DAY(date_time) AS g_day,
       HOUR(date_time) AS g_hour 
FROM table1 
WHERE date_time >= NOW() - INTERVAL 1 DAY 
GROUP BY g_day, g_hour

【讨论】:

  • 感谢 Alex 提供的遮阳篷。您的查询返回的结果与“spencer7593”代码相同。当他解释底层结构时,我赞成他的遮阳篷。这也可能对其他用户有用。
【解决方案2】:

MySQL 无法确定 GROUP BY 子句中的表达式和 SELECT 列表中的表达式之间的功能依赖关系。

SELECT 列表中的非聚合表达式 (DATE_FORMAT(date_time, '%H:%i') 包含分钟组件。GROUP BY 子句将按小时将行折叠成组。所以 minutes 是不确定的...我们知道它会来自组中的某个行,但不能保证是哪一个。

(对ONLY_FULL_GROUP_BY的问题引用似乎表明我们对不确定值有所了解......)

最简单(最少)的更改修复方法是将该表达式包装在 MINMAX 函数中。

 SELECT MAX(t.counter)                          AS `max`
      , MIN(t.counter)                          AS `min`
      , MIN(DATE_FORMAT(t.date_time,'%H:%i'))   AS `dt`
   FROM table1 t
  WHERE t.date_time >= NOW() - INTERVAL 1 DAY 
  GROUP
     BY YEAR(t.date_time)
      , MONTH(t.date_time)
      , DAY(t.date_time)
      , HOUR(t.date_time)
  ORDER
     BY YEAR(t.date_time)
      , MONTH(t.date_time)
      , DAY(t.date_time)
      , HOUR(t.date_time)

如果我们希望以特定顺序返回行,我们应该包含一个 ORDER BY 子句,而不是依赖于 MySQL 特定的扩展或 GROUP BY 的行为(可能会在未来的版本中消失。)


在 SELECT 列表中不包括 GROUP BY 年、月、日和不包括这些值有点奇怪。 (这样做并不是无效的,只是有点奇怪。WHERE 子句中的条件保证date_time 的跨度不超过 24 小时。

我的偏好是在与 SELECT 列表中的非聚合相同的表达式上执行 GROUP BY。如果我需要超过 24 小时,我会包含日期组件:

 SELECT MAX(t.counter)                             AS `max`
      , MIN(t.counter)                             AS `min`
      , DATE_FORMAT(t.date_time,'%Y-%m-%d %H:00') + INTERVAL 0 DAY AS `dt`
   FROM table1 t
  WHERE t.date_time >= NOW() - INTERVAL 1 DAY 
  GROUP
     BY DATE_FORMAT(t.date_time,'%Y-%m-%d %H:00') + INTERVAL 0 DAY
  ORDER
     BY DATE_FORMAT(t.date_time,'%Y-%m-%d %H:00') + INTERVAL 0 DAY

--或--

如果我们总是知道 date_time 只值一天,并且我们只想返回小时,那么我们可以按小时分组。与 SELECT 列表中的表达式相同。

 SELECT MAX(t.counter)                             AS `max`
      , MIN(t.counter)                             AS `min`
      , DATE_FORMAT(t.date_time,'%H:00')           AS `dt`
   FROM table1 t
  WHERE t.date_time >= NOW() - INTERVAL 1 DAY 
  GROUP
     BY DATE_FORMAT(t.date_time,'%H:00')
      , DATE_FORMAT(t.date_time,'%Y-%m-%d %H')
  ORDER
     BY DATE_FORMAT(t.date_time,'%Y-%m-%d %H')

【讨论】:

  • 感谢 spencer7593 的清晰解释。这确实解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-18
  • 1970-01-01
  • 2019-09-21
  • 1970-01-01
  • 2010-10-06
  • 2017-01-22
  • 2017-04-30
相关资源
最近更新 更多