it-roy-ru.com

Ошибка, связанная с 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 или мне нужно еще что-нибудь сделать?

Дайте мне знать, если вам нужна дополнительная информация.

353
Dan Bemowski

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

Когда SELECTing столбец, который не является частью 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
288
davmos

Вы можете попытаться отключить параметр 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, поэтому его необходимо удалить.

298
WeiYuan

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

Начиная с MySQL 5.7.5, режим SQL по умолчанию включает ONLY_FULL_GROUP_BY , что означает, что когда вы группируете строки и затем выбираете что-то из этих групп, вам нужно явно сказать из какой строки следует сделать этот выбор. Mysql needs to know which row in the group you're looking for, which gives you two options

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

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

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

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

    [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. Введите esc для выхода из режима ввода

  6. Введите :wq, чтобы сохранить и закрыть vim.
  7. Введите Sudo service mysql restart, чтобы перезапустить MySQL.
156
Ajai

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

С MySQL 5.7 документов :

Вы можете достичь того же эффекта, не отключая 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;
46
Italo Borssatto

Я постараюсь объяснить вам, о чем эта ошибка.
Начиная с 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`

enter image description here

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

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

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

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

Который полностью действителен, согласно правилам MySQL.
И так далее.

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

42
Abraham Tugalov

Я использую 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-Homesteadhttps://mattstauffer.co/blog/strict-mode- и-другое-MySQL-настройки-в-Laravel-5-2

36
Ryan

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

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
PiyaChakraborty

Добавление строк (упомянуто ниже) в файле: /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)

13
Jagdeep Singh

Для Mac:

1. Скопируйте файл по умолчанию 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. Перезапустите сервер MySQL.

mysql.server restart
9
Tanvir Hasan Anick

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

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

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

6
Braham Dev Yadav

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

  1. https://stackoverflow.com/a/20074634/1066234
  2. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

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

проблематичен:

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 - Запрос: SELECT COUNT (*) как попытки, SUM (истекшее) как elapsedtotal, userid, timestamp, questionid, answerid, SUM (правильное) как правильное, elapsed, ipaddress FROM gameplay WHERE timeSump>> DATE (СЕЙЧАС (), ИНТЕРВАЛ 1 ДЕНЬ) И ИДЕНТИФИКАТОР = 1

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

4
Kai Noack

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

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

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

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

2
Gangai Johann

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

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

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

2
micaball

Извиняюсь за то, что не использовал ваш точный 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
Harry Bosh