Ошибка, связанная с only_full_group_by при выполнении запроса в MySql

Я обновил свою систему и установил MySql 5.7.9 с php для веб-приложения, над которым я работаю. У меня есть запрос, который динамически создается, и при работе в более старых версиях MySql он отлично работает. С момента обновления до 5.7 я получаю эту ошибку:

Выражение # 1 списка SELECT не находится в предложении GROUP BY и содержит неагрегированный столбец "support_desk.mod_users_groups.group_id", который функционально не зависит от столбцов в предложении GROUP BY; это несовместимо с sql_mode = only_full_group_by

Обратите внимание на страницу руководства для Mysql 5.7 на тему Режимы сервера SQL.

Это запрос, который вызывает у меня проблемы:

SELECT mod_users_groups.group_id AS 'value', 
       group_name AS 'text' 
FROM mod_users_groups
LEFT JOIN mod_users_data ON mod_users_groups.group_id = mod_users_data.group_id 
WHERE  mod_users_groups.active = 1 
  AND mod_users_groups.department_id = 1 
  AND mod_users_groups.manage_work_orders = 1 
  AND group_name != 'root' 
  AND group_name != 'superuser' 
GROUP BY group_name 
HAVING COUNT(`user_id`) > 0 
ORDER BY group_name

Я сделал некоторые ошибки в этом вопросе, но я не понимаю only_full_group_by достаточно, чтобы выяснить, что мне нужно сделать, чтобы исправить запрос. Могу ли я просто отключить опцию only_full_group_by, или есть что-то еще, что мне нужно сделать?

Сообщите мне, если вам нужна дополнительная информация.

+379
источник поделиться
16 ответов

Я бы просто добавил group_id в GROUP BY.

Когда SELECT столбца, который не является частью GROUP BY, может быть несколько значений для этого столбца внутри групп, но будет только место для одного значения в результатах. Таким образом, база данных обычно должна быть рассказана точно, как сделать эти несколько значений одним значением. Обычно это выполняется с помощью агрегатной функции типа COUNT(), SUM(), MAX() и т.д.... Обычно я говорю, потому что большинство других популярных систем баз данных настаивают на этом. Однако в MySQL до версии 5.7 поведение по умолчанию было более прощающим, потому что оно не будет жаловаться, а затем произвольно выбирает любое значение! Он также имеет функцию ANY_VALUE(), которая может быть использована в качестве другого решения для этого вопроса, если вам действительно необходимо такое же поведение, как и раньше. Эта гибкость стоит дорого, потому что она недетерминирована, поэтому я бы не рекомендовал ее, если у вас нет веских оснований для ее использования. MySQL по умолчанию по умолчанию использует параметр only_full_group_by, поэтому лучше всего привыкнуть к нему и выполнить ваши запросы.

Так почему мой простой ответ выше? Я сделал пару предположений:

1) group_id является уникальным. Кажется разумным, это "идентификатор" в конце концов.

2) group_name также уникален. Это может быть не такое разумное предположение. Если это не так, и у вас есть дубликат group_names, и вы затем следуете моему совету, чтобы добавить group_id в GROUP BY, вы можете обнаружить, что теперь у вас больше результатов, чем раньше, потому что группы с тем же именем будут теперь имеют отдельные строки в результатах. Для меня это было бы лучше, чем скрытие этих дублирующих групп, потому что база данных спокойно выбрала значение произвольно!

Это также хорошая практика, чтобы квалифицировать все столбцы с их именем таблицы или псевдонимами, когда задействовано более одной таблицы...

SELECT 
  g.group_id AS 'value', 
  g.group_name AS 'text' 
FROM mod_users_groups g
LEFT JOIN mod_users_data d ON g.group_id = d.group_id 
WHERE g.active = 1 
  AND g.department_id = 1 
  AND g.manage_work_orders = 1 
  AND g.group_name != 'root' 
  AND g.group_name != 'superuser' 
GROUP BY 
  g.group_name, 
  g.group_id 
HAVING COUNT(d.user_id) > 0 
ORDER BY g.group_name
+314
источник

Вы можете попытаться отключить настройку only_full_group_by, выполнив следующее:

mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

MySQL 8 не принимает NO_AUTO_CREATE_USER, поэтому его необходимо удалить.

+327
источник

вы можете отключить предупреждающее сообщение, как описано в других ответах, или вы можете понять , что происходит, и исправить его.

Начиная с MySQL 5.7.5, по умолчанию SQL-режим включает ONLY_FULL_GROUP_BY, что означает, когда вы группируете строки и затем выбираете что-то из этих групп, вам нужно явно указать, из какой строки должен быть выбран этот выбор. Mysql должен знать, какую строку в группе вы ищете, что дает вам два варианта

Mysql должен знать, какую строку в группе вы ищете, что дает вам две опции

  • Вы также можете добавить столбец, который вы хотите в оператор группы group by rect.color, rect.value, который может быть тем, что вы хотите в некоторых случаях, иначе возвратите повторяющиеся результаты с тем же цветом, который вам может не понадобиться.
  • вы также можете использовать агрегатные функции для mysql, чтобы указать, какую строку вы ищете внутри групп, таких как AVG() MIN() MAX() полный список
  • И, наконец, вы можете использовать ANY_VALUE(), если вы уверены, что все результаты внутри группы одинаковы. doc
+299
источник

Если вы не хотите вносить какие-либо изменения в свой текущий запрос, выполните следующие шаги:

  • бродяга ssh в вашу коробку
  • Тип: sudo vim /etc/mysql/my.cnf
  • Прокрутите вниз до конца файла и введите A, чтобы войти в режим вставки
  • Скопируйте и вставьте

    [mysqld]
    sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    
  • Введите esc для выхода из режима ввода

  • Введите :wq, чтобы сохранить и закрыть vim.
  • Введите sudo service mysql restart, чтобы перезапустить MySQL.
+163
источник

Используйте ANY_VALUE() для ссылки на неагрегированный столбец.

Из MySQL 5.7 docs:

Вы можете добиться такого же эффекта без отключения ONLY_FULL_GROUP_BYиспользуя ANY_VALUE() для ссылки на неагрегированный столбец.

...

Этот запрос может быть недействительным при включенном ONLY_FULL_GROUP_BY, поскольку столбец неагрегированных адресов в списке выбора не указан в предложении GROUP BY:

SELECT name, address, MAX(age) FROM t GROUP BY name;

...

Если вы знаете, что для данного набора данных каждое значение имени на самом деле однозначно определяет значение адреса, адрес эффективно функционально зависит от имени. Чтобы сообщить MySQL о принятии запроса, вы можете использовать функцию ANY_VALUE():

SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;
+50
источник

Я попытаюсь объяснить вам, что это за ошибка.
Начиная с MySQL 5.7.5, опция ONLY_FULL_GROUP_BY включена по умолчанию.
Таким образом, согласно стандарту SQL92 и ранее:

не разрешает запросы, для которых выбранный список, условие HAVING, или ORDER BY относятся к неагрегированным столбцам, которые не называются в предложении GROUP BY и функционально зависит от (однозначно определяется столбцами GROUP BY

(больше в документах)

Итак, например:

SELECT * FROM `users` GROUP BY `name`;

После выполнения запроса вы получите сообщение об ошибке.

# 1055 - Выражение # 1 списка SELECT не находится в предложении GROUP BY и содержит неагрегированный столбец "testsite.user.id", который не является функционально зависит от столбцов в предложении GROUP BY; это несовместимо с sql_mode = only_full_group_by

Почему?
Поскольку MySQL точно не понимает, какие определенные значения из сгруппированных записей извлекаются, и это точка.

т.е. скажем, у вас есть эти записи в таблице users:
Yo

И вы выполните недопустимый запрос, показанный выше.
И вы получите ошибку, показанную выше, потому что есть 3 записи с именем John, и это хорошо, но все они имеют разные значения полей email.
Таким образом, MySQL просто не понимает, какие из них возвращаются в результирующую сгруппированную запись.

Вы можете исправить эту проблему, просто изменив свой запрос следующим образом:

SELECT `name` FROM `users` GROUP BY `name`

Кроме того, вы можете добавить больше полей в секцию SELECT, но вы не можете сделать это, если они не агрегированы, но есть костыль, который вы могли бы использовать (но сильно не рекомендовано):

SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name`

введите описание изображения здесь

Теперь вы можете спросить, почему использование ANY_VALUE сильно не рекомендуется?
Поскольку MySQL точно не знает, какое значение сгруппированных записей извлекается, и используя эту функцию, вы просите ее получить любую из них (в этом случае было получено электронное письмо первой записи с именем = Джон).
Точно я не могу придумать какие-либо идеи о том, почему вы хотите, чтобы такое поведение существовало. Пожалуйста, если вы меня не понимаете, читайте больше о том, как работает группировка в MySQL, это очень просто.

И к концу, вот еще один простой, но действительный запрос.
Если вы хотите запросить общий подсчет пользователей в соответствии с доступными возрастами, вы можете записать этот запрос

SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`;

Что является полноправным, в соответствии с правилами MySQL.
И так далее. Важно понять, в чем проблема, и только потом записать решение.

+45
источник

Я использую Laravel 5.3, mysql 5.7.12, на laravel homestead (0.5.0, я считаю)

Даже после явной настройки редактирования /etc/mysql/my.cnf для отражения:

[mysqld]
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Я все еще получал ошибку.

Мне пришлось изменить config/database.php с true на false:

    'mysql' => [
        'strict' => false, //behave like 5.6
        //'strict' => true //behave like 5.7
    ], 

Дальнейшее чтение:

https://laracasts.com/discuss/channels/servers/set-set-sql-mode-on-homestead https://mattstauffer.co/blog/strict-mode-and-other-mysql-customizations-in-laravel-5-2

+37
источник

Если вы используете wamp 3.0.6 или любую верхнюю версию, отличную от версии 2.5, вы можете столкнуться с этой проблемой, во-первых, проблема связана с sql. вы должны указать поля соответственно. но есть другой способ, с помощью которого вы можете его решить. нажмите зеленую иконку wamp. mysql- > mysql settings- > sql_mode- > none. или с консоли вы можете изменить значения по умолчанию.

mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+18
источник

Добавление строк (см. ниже) в файле:/etc/mysql/my.cnf

[mysqld]
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Работайте отлично. Версия сервера: 5.7.18-0ubuntu0.16.04.1 - (Ubuntu)

+15
источник

Для mac:

1.Copy по умолчанию my-default.cnf в /etc/my.cnf

sudo cp $(brew --prefix mysql)/support-files/my-default.cnf /etc/my.cnf

2. Измените sql_mode в my.cnf, используя ваш любимый редактор и установите его на

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

сервер 3.Restart MySQL.

mysql.server restart
+9
источник

Для localhost/wampserver 3 мы можем установить sql-mode = user_mode, чтобы удалить эту ошибку:

click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode

затем перезапустите wamp или apache

+6
источник

Вот что помогло мне понять всю проблему:

И в следующем примере проблемного запроса.

Проблемные:

SELECT COUNT(*) as attempts, SUM(elapsed) as elapsedtotal, userid, timestamp, questionid, answerid, SUM(correct) as correct, elapsed, ipaddress FROM `gameplay`
                        WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 1 DAY)
                        AND cookieid = #

Решено, добавив это к концу:

  GROUP BY timestamp, userid, cookieid, questionid, answerid, elapsed, ipaddress

Примечание. См. сообщение об ошибке в PHP, в котором указано, где находится проблема.

Пример:

Ошибка запроса MySQL 1140: в агрегированном запросе без GROUP BY выражение # 4 списка SELECT содержит неагрегированный столбец "db.gameplay.timestamp"; это несовместимо с sql_mode = only_full_group_by - Query: SELECT COUNT (*) в качестве попыток, SUM (истек) как elapsedtotal, userid, timestamp, questionid, answerid, SUM (правильно) как правильно, истек, ipaddress FROM gameplay                             WHERE timestamp >= DATE_SUB (NOW(), INTERVAL 1 DAY)                             И userid = 1

В этом случае выражение # 4 отсутствовало в группе GROUP BY.

+5
источник

Вы можете добавить unique index в group_id; если вы уверены, что group_id уникален.

Он может решить ваш случай без изменения запроса.

Поздний ответ, но он еще не упоминался в ответах. Возможно, он должен заполнить уже исчерпывающие ответы. По крайней мере, это разрешило мой случай, когда мне пришлось разбивать таблицу со слишком большим количеством полей.

+3
источник

Если у вас есть эта ошибка с Symfony с помощью построителя запросов доктрины, и если эта ошибка вызвана orderBy:

Обратите внимание на select столбец, который вы хотите groupBy, и используйте addGroupBy вместо groupBy:

$query = $this->createQueryBuilder('smth')->addGroupBy('smth.mycolumn');

Работает на Symfony3 -

+2
источник

Извините, что не использовал ваш точный SQL

Я использовал этот запрос для преодоления предупреждения Mysql.

SELECT count(*) AS cnt, `regions_id`
FROM regionables 
WHERE `regionable_id` = '115' OR `regionable_id` = '714'
GROUP BY `regions_id`
HAVING cnt > 1

обратите внимание на ключ для меня

count(*) AS cnt
0
источник

Зайдите в mysql или phpmyadmin и выберите базу данных затем просто выполните этот запрос, и он будет работать. Это хорошо работает для меня.

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос