Ошибка, связанная с 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
, или есть что-то еще, что мне нужно сделать?
Сообщите мне, если вам нужна дополнительная информация.
Ответы
Ответ 1
Я бы просто добавил 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
Ответ 2
Вы можете попытаться отключить настройку 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
, поэтому его необходимо удалить.
Ответ 3
вы можете отключить предупреждающее сообщение, как описано в других ответах, или вы можете понять , что происходит, и исправить его.
Начиная с MySQL 5.7.5, по умолчанию SQL-режим включает ONLY_FULL_GROUP_BY, что означает, когда вы группируете строки и затем выбираете что-то из этих групп, вам нужно явно указать, из какой строки должен быть выбран этот выбор.
![Mysql должен знать, какую строку в группе вы ищете, что дает вам два варианта]()
Mysql должен знать, какую строку в группе вы ищете, что дает вам две опции
- Вы также можете добавить столбец, который вы хотите в оператор группы
group by rect.color, rect.value
, который может быть тем, что вы хотите в некоторых случаях, иначе возвратите повторяющиеся результаты с тем же цветом, который вам может не понадобиться.
- вы также можете использовать агрегатные функции для mysql, чтобы указать, какую строку вы ищете внутри групп, таких как
AVG()
MIN()
MAX()
полный список
- И, наконец, вы можете использовать
ANY_VALUE()
, если вы уверены, что все результаты внутри группы одинаковы. doc
Ответ 4
Если вы не хотите вносить какие-либо изменения в свой текущий запрос, выполните следующие шаги:
- бродяга 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.
Ответ 5
Используйте 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;
Ответ 6
Я попытаюсь объяснить вам, что это за ошибка.
Начиная с 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
:
И вы выполните недопустимый запрос, показанный выше.
И вы получите ошибку, показанную выше, потому что есть 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.
И так далее.
Важно понять, в чем проблема, и только потом записать решение.
Ответ 7
Я использую 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
Ответ 8
Если вы используете 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';
Ответ 9
Добавление строк (см. ниже) в файле:/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)
Ответ 10
Для 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
Ответ 11
Для localhost/wampserver 3 мы можем установить sql-mode = user_mode, чтобы удалить эту ошибку:
click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode
затем перезапустите wamp или apache
Ответ 12
Вот что помогло мне понять всю проблему:
И в следующем примере проблемного запроса.
Проблемные:
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.
Ответ 13
Вы можете добавить unique index
в group_id
; если вы уверены, что group_id
уникален.
Он может решить ваш случай без изменения запроса.
Поздний ответ, но он еще не упоминался в ответах. Возможно, он должен заполнить уже исчерпывающие ответы. По крайней мере, это разрешило мой случай, когда мне пришлось разбивать таблицу со слишком большим количеством полей.
Ответ 14
Если у вас есть эта ошибка с Symfony с помощью построителя запросов доктрины, и если эта ошибка вызвана orderBy:
Обратите внимание на select
столбец, который вы хотите groupBy
, и используйте addGroupBy
вместо groupBy
:
$query = $this->createQueryBuilder('smth')->addGroupBy('smth.mycolumn');
Работает на Symfony3 -
Ответ 15
Извините, что не использовал ваш точный 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
Ответ 16
Зайдите в mysql или phpmyadmin и выберите базу данных
затем просто выполните этот запрос, и он будет работать.
Это хорошо работает для меня.
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));