MYSQL max () и группа по ошибке: only_full_group_by - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть вопрос о запросе MySQL, который регистрирует ошибки с момента обновления MySQL-5.7.Ошибка "only_full_group_by", которая будет устранена в стеке потока.

Во многих ответах указывается не отключать эту опцию, а улучшать ваш 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)

, как я понимаю из сообщения об ошибке, я пропускаю один из элементов из причины SELECT в причине GROUP BY.Но, тем не менее, я перебираю / удаляю / добавляю элементы, но не получаю результат, полученный до обновления до MySQL-5.7.

Я пытался выполнить подзапрос основного запроса, чтобы улучшить запрос SQL.Но почему-то я не могу воссоздать результаты.

Что мне не хватает?

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

MySQL не может определить функциональную зависимость ... между выражениями в предложении GROUP BY и выражениями в списке SELECT.

Неагрегированное выражение в списке SELECT (DATE_FORMAT(date_time, '%H:%i') включает компонент минут. Предложение GROUP BY собирается свернуть строки в группы всего за час. Таким образом, значение минуты неопределенны ... мы знаем, что это произойдет из какого-то ряда в группе, но нет гарантии, какой именно.

(Ссылка на вопрос ONLY_FULL_GROUP_BY, кажется, указывает на то, что у нас есть некоторое понимание неопределенных значений ...)

Самое простое (наименьшее) исправление изменений - заключить это выражение в функцию MIN или MAX.

 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 (которое может исчезнуть в будущих выпусках.)


Немного странно делать GROUP BY год, месяц, день и не включать эти значения в список SELECT. (Это не является недействительным, просто странно. Условия в предложении WHERE гарантируют, что у нас не более 24 часов для date_time.

Я бы предпочел сделать GROUP BY в том же выражении, что и неагрегат в списке SELECT. Если бы мне понадобилось больше 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')
0 голосов
/ 12 ноября 2018
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
...