Помилка, пов’язана з only_full_group_by при виконанні запиту в MySql


442

Я оновив свою систему і встановив 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варіант, чи потрібно щось ще зробити?

Повідомте мене, якщо вам потрібна додаткова інформація.


тут я знайшов рішення stackoverflow.com/a/7588442/612987
Васім А.

21
Це повинно бути найбільш перекрученим повідомленням про помилку, з якого я коли-небудь стикався.
Рольф

2
@Rolf Ви бачили помилку в тому ж типі проблеми в Oracle? " not a GROUP BY expression" Це все. Вони також можуть просто мати числовий код помилки і взагалі немає повідомлення.
Білл

Відповіді:


359

Я б просто додати 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

Дякую, що працює чудово. Я також згоден, що мені потрібно кваліфікувати колонки. Це виключає будь-яку можливість неоднозначності. Зараз я переробляю код. Дякуємо мільйон за допомогу.
Дан Бемовський

У мене навіть немає GROUP BYзапиту в запиті, але я отримую цю помилку.
aitchkhan

@HaroonKhan, це звучить як нове запитання. Дайте мені знати, якщо ви запитаєте, і я погляну.
davmos

2
У MySQL 5.7 вони встановлюють властивість, яка вимагає, щоб усі непоєднані поля в запиті були GROUP BY. Отже, запит типу SELECT a, SUM (b) ВІД таблиці; означає, що поле "a" повинно бути в групі BY. Тож якщо у вас немає GROUP BY, ви повинні додати її до запиту. Вся справа в тому, якщо у вас є принаймні одне сукупне поле в частині SELECT запиту.
користувач1567291

мені довелося виправити "попередження", додавши елемент до групи за допомогою пункту, як було запропоновано у цій відповіді, оскільки жодна відповідь, що передбачає виправлення sql_mode, не працювала. (мій MySQL був у збереженій процедурі, але не знаю, чи це було актуально)
zzapper

355

Ви можете спробувати відключити 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тому його потрібно видалити.


85
Це
обробка

1
Оновлення /etc/mysql/my.cnf (як показано нижче) є більш стійким рішенням, оскільки налаштування за замовчуванням, як правило, повертаються після перезавантаження. А для тих, хто каже, що вам слід виправити запит, тоді це не зовсім просто, коли вам потрібен швидкий налагоджувальний запит і виконайте такі дії, як SELECT COUNT(*), t.* FROM my_table t GROUP BY colі у вас є 20-50 стовпців, чи хочете ви витратити стільки часу на додавання кожного стовпця до групувати по?
Shadoweb

3
Це "рішення" є досить небезпечним. Ви можете активувати раніше відключені режими, сліпо змінюючи їх, а не видаляти лише один прапор налаштувань. Це може призвести до несподіваної поведінки, а в гіршому випадку призведе до неправильних результатів або припинити роботу вашої програми повністю. Тому я вважаю цю відповідь неправильною.
Кріс С.

1
Я зробив це наполегливим шляхом оновлення, з’ясувавши свій поточний sql_mode через, SELECT @@sql_mode;а потім додав результат звідти до my.cnf:sql_mode=[list of modes from query, minus ONLY_FULL_GROUP_BY]
wbharding

323

ви можете вимкнути попереджувальне повідомлення, як пояснено в інших відповідях, або ви можете зрозуміти, що відбувається, і виправити це.

Як і в MySQL 5.7.5, режим SQL за замовчуванням включає ONLY_FULL_GROUP_BY, що означає, коли ви групуєте рядки і потім вибираєте щось із цих груп, вам потрібно чітко сказати, з якого рядка повинен бути зроблений цей вибір. Mysql повинен знати, який рядок у групі, яку ви шукаєте, що дає вам два варіанти

Mysql повинен знати, який рядок у групі, яку ви шукаєте, що дає вам два варіанти

  • Ви також можете додати потрібний стовпець до групового оператора, group by rect.color, rect.valueякий може бути тим, що ви хочете в деяких випадках, інакше повернеться дублікати результатів того ж кольору, який ви не хочете.
  • ви також можете використовувати сукупні функції mysql, щоб вказати, який рядок ви шукаєте всередині груп, як-от AVG() MIN() MAX() повний список
  • І, нарешті, ви можете використовувати, ANY_VALUE()якщо ви впевнені, що всі результати в групі однакові. док

25
Я не думаю, що MySQL підтримує FIRST()метод / функцію?
Бен Гільдія

3
Я вважаю, що MySQL (принаймні до 5.7) за замовчуванням приймає перше значення, яке воно знаходить у групі. Отже, FIRST () не існує, оскільки він був синонімом самої функції GROUP BY.
DrDamnit

2
@DrDamnit, я вважаю, що це більше нагадувало випадковий вибір у таких випадках, що призвело до плутанини і, таким чином, уможливилося ONLY_FULL_GROUP_BYза замовчуванням
azerafati

6
Я вже знав відповідь, але приклад із кольоровим прямокутником так легко зрозуміти, я повторно його використаю наступного разу, коли хтось запитає мене про це.
user327961

@azerafati - це щось на кшталт FIRST () або якийсь запит, який можна використовувати для отримання першого значення, як у мене.
Харіс

169

Якщо ви не хочете вносити жодних змін у поточний запит, виконайте наведені нижче дії -

  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.

Тільки голова до всіх Vagrant користувачів, які намагаються використовувати це з AdonisJS, вам це потрібно для запуску paginateфункції.
Майкл Дж. Калкінс

Очевидно, це стосується не лише користувачів Vagrant, але й будь-якої системи Unix. Зауважте, що для мене було розташування my.cnfфайлу /etc. Альси відзначають новий синтаксис з тих пірMySQL 5.7.8: sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
Валентин Грегоар

Мені працює у Mint 19.3 (ubuntu 18.04) дякую
Марко Лопес

71

Використовуйте ANY_VALUE()для позначення неагрегованого стовпця.

SELECT name,           address , MAX(age) FROM t GROUP BY name; -- fails
SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name; -- works

З 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;

1
Як хтось, хто вже якийсь час стикався з цією проблемою - мені особливо подобається це рішення, оскільки воно не вимагає від вас змін будь-яких файлів чи налаштувань у вашому налаштуванні MySQL. Цікаво, що я ANY_VALUE ніде більше не бачу згадок у подібних дискусіях - це чудово працює для мене з моєю GROUP_BY contains nonaggregated columnпомилкою.
adstwlearn

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 і містить неагреговану колонку 'testingite.user.id', яка функціонально не залежить від стовпців у пункті GROUP BY; це несумісно з sql_mode = only_full_group_by

Чому?
Оскільки MySQL точно не розуміє, які певні значення згрупувати записи, щоб отримати, і в цьому справа.

IE дозволяє сказати, що у вас є ці записи в 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.
І так далі.

Важливо зрозуміти, в чому саме полягає проблема, і лише після цього записати рішення.


Дякую за цю приємну відповідь. Що робити, якщо я також хочу, щоб електронні листи були як масив у групі результатів?
Йосія

1
Ви завжди можете виконати обов'язкове поле GROUP_CONCAT, щоб отримати кожен запис, який там є.
Авраам Тугалов

Ой! так що є спосіб! Будь ласка, допоможіть мені в цьому питанні
Йосія

Дякую за цю чудову відповідь. Що робити, якщо я хочу зробити GROUP BY DAY(created_date)? Схоже, це не працює, якщо DAY()його додано.
ескімос

41

Я використовую Laravel 5.3, mysql 5.7.12, в садибі laravel (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


Данг! Це було корисно для користувачів Laravel. +1 для цього.
Окафор Т Косісо

20

Якщо ви використовуєте 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';

фантастично, спираючись на те, що він сказав, вставити команду show variables like '%sql_mode%';в командний рядок mysql, налаштування sql_mode покаже
Джейд Хан

19

Додавання рядків (згадка нижче) у файл: /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)


1
ти використовуєш RDS?
Mubasshir Pawle

@MubasshirPawle Ні
Jagdeep Singh

16

Перейдіть до mysql або phpmyadmin та виберіть базу даних, тоді просто виконайте цей запит, і він спрацює. Це працює добре для мене.

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

Чудово .. Дякую :)
mohitesachin217

Моє задоволення :) @mohit
Аніл Гупта

Врятувало мені тону часу, дякую.
JoeRaid

1
Ласкаво просимо @TharinduEranga
Аніл Гупта

1
Але проблема з рішенням полягає в тому, що кожен раз, коли я перезавантажую mysql, мені потрібно виконати запит заново. Це означає, що рішення не є постійним або стійким.
Мушфікур Рахман

10

Для 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

Дякую, працювали і для мене. Але я використовую mysql за замовчуванням Mac, тому у мене немає пивоваріння. Просто sudo cp my-default.cnf /etc/my.cnf
Майк Нгуен

2
@Mike Nguyen sudo cp /usr/local/mysql-5.7.17-macos10.12-x86_64/support-files/my-default.cnf /etc/my.cnf sudo vi /etc/my.cnf встановити sql_model sql_mode = STRICT_TRANS_T , NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION Перезавантажте сервер MySQL.
Йонг Гао

7

Саме це допомогло мені зрозуміти всю проблему:

  1. https://stackoverflow.com/a/20074634/1066234
  2. https://dev.mysql.com/doc/refman/5.7/uk/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 (пропущений) як минулий, загальний, userid, часова мітка, питальний, answerid, SUM (правильний) як правильний, пропущений, ipaddress ВІД ігрового режиму WHERE timetamp> = DATE_SUB (ЗАРАЗ (), ІНТЕРВАЛ 1 ДЕНЬ) І userid = 1

У цьому випадку вираз №4 відсутній у групі BY.


1
Дякую за вказівку stackoverflow.com/questions/20074562 / ...
cwhsu

Чудова відповідь для вирішення цього питання. Дуже дякую
Hansana Athukorala

7

Для localhost / wampserver 3 ми можемо встановити sql-mode = user_mode для видалення цієї помилки:

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

потім перезапустіть wamp або apache


1
Я знаю, що це може бути не довгостроковим вирішенням цієї проблеми, але це, безумовно, допомогло зараз. Моя хостингова компанія Go Daddy використовує MySQL V5.6.33, а WampServer 3 використовує MySQL V5.7.14. Дякуємо за це швидке вирішення
Alan N

4

Ви можете додати unique indexдо group_id; якщо ви впевнені, що group_idце унікально.

Він може вирішити вашу справу, не змінюючи запит .

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


2

Якщо у вас є помилка з Symfony, використовуючи конструктор запитів доктрин , і якщо ця помилка викликана orderBy :

Зверніть увагу на selectпотрібний стовпець groupByта використовуйте addGroupByзамість groupBy:

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

Працює на Symfony3 -


1

Вибачте за те, що не використовуєте точний 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.