Mysql group by не работает

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Страниц: 1

#1 14.11.2012 16:12:09

распространенная ошибка в запросах с group by

В запросе с группировкой в части перечисления полей (то, что идет после SELECT) по стандарту SQL можно указывать ТОЛЬКО те поля, по которым идет группировка, или которые используются с групповыми функциями (sum, max, group_concat, . )
MySQL не генерирует ошибку, если запрос не удовлетворяет данному правилу. Однако результат часто бывает не тот, который ожидается, так как для полей без групповых функций и не указанных в части GROUP BY выбирается произвольная строка из группы.

Для примера рассмотрим таблицу сообщений, имеющую поля (`user_id`, `post`, `time`), в которой хранится id пользователя, текст сообщения и время добавления сообщения. Пусть мы хотим выбрать последнее сообщение каждого юзера. Порой можно увидеть такие конструкции:

Оба этих запроса неверные. В первом для каждого user_id будет выбрана произвольная строка с данным user_id после чего эти строки будут отсортированы по времени. Во втором, для каждого user_id будет выбрано max(`time`) и значение поля `post` из случайной строки с данным user_id, а не из той, которая соответствует max(`time`). А если результат правильный, то это не более чем случайность.

Проиллюстрируем ситуацию на простом примере.

MariaDB [ test ] > select user_id, post, ` time ` from test_table;
+ ———+———+———————+
| user_id | post | time |
+ ———+———+———————+
| 1 | post 1 | 2012 -10 -14 16 : 51 : 26 |
| 1 | post 2 | 2012 -11 -12 16 : 51 : 26 |
| 1 | post 3 | 2012 -11 -15 16 : 51 : 26 |
+ ———+———+———————+
3 rows in set ( 0.14 sec )

Читайте также:  Не работает обогрев зеркал уаз патриот

MariaDB [ test ] > select user_id, post, max ( ` time ` ) from test_table group by user_id;
+ ———+———+———————+
| user_id | post | max ( ` time ` ) |
+ ———+———+———————+
| 1 | post 1 | 2012 -11 -15 16 : 51 : 26 |
+ ———+———+———————+

Как видим значение поля `post` выбрано «неверно». В кавычках потому что неверно с человеческой точки зрения — мы ожидали увидеть значение, соответствующее максимальному времени, т.е. ‘post 3’. А сервер MySQL взял значение поля post из первой попавшейся строки с user_id =1, так как никаких указаний относительно этого поля ему не поступало.

Правильным решением данной задачи будет найти сначала комбинации (`user_id`,`time`), а по ним уже выбрать недостающее поле `post`. Для простоты предположим, что у пользователя не может быть двух одновременных сообщений, т.е. комбинация (`user_id`,`time`) однозначно идентифицирует строку. Тогда нужный нам запрос будет выглядеть так:

При определенных условиях существует способ решить задачу без использования JOIN. Пусть поле `time` имеет тип данных DATETIME, т.е. принимает значения вида ‘2012-02-15 01:47:19’. Тогда мы знаем, что значение этого поля всегда будет иметь ширину в 19 символов. В этом случае мы можем искать максимум не от поля `time`, а от строки, склеивающей значения полей `time` и `post`, а потом результат разбить назад на составляющие.

Источник

Как работает GROUP BY в MySQL?

Вопрос по sql по клаузуле GROUP BY .

Рассмотрим группировку по ОДНОМУ столбцу. Пример:

То есть, в столбце DEPARTMENT_ID ищется уникальное (похоже на DISTINCT ) значение отдела, например, 30, затем ищутся все строки, где упоминается отдел 30 в данной таблице, из этих строк берутся значения из столбца SALARY и суммируются ( SUM ). Потом ищется другой покупатель и все повторяется. В итоге я получаю сколько получил вообще денег каждый отдел.

Не понимаю момент: у меня есть 6 строк, в которых есть столбец DEPARTMENT_ID со значением 30. Какая из строк пойдет в таблицу- SELECT и почему? То есть, в таблице Employees было шесть строк с DEPARTMENT_ID 30, а в таблице- SELECT такая строка только одна. Как вообще эта группировка работает?

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

2 ответа 2

Добавлю с примером запросов и вывода GROUP BY по двух полях. Смотреть можно по таблице в которую, например, сохраняеться какой пользователь (user_id) вносил деньги, на какой счет (account) и сколько (balance). Например, нужно узнать сколько каждый пользователь внес на каждый из своих счетов.

Работает GROUP BY по двум полям так же как и по одному, сначала сортирует, а потом смотрит, если оба значения в строке такие же как и в предыдущей строке, тогда групирует эти строки. Если хотя бы одно значение не такое как в предыдущей строке, тогда групировки не будет. Для 3 и больше полей GROUP BY работает так же.

В выборку после group by не попадет ни одна из изначальных строк. На выходе агрегат — сумма данных в нужном разрезе. К колонкам, к которым вы явно не применили никаких групповых функций (таких как sum() ), будет применена функция «первое попавшееся». Причем только в MySQL и только при выключенной опции ONLY_FULL_GROUP_BY . В остальных СУБД запрос, в котором хотя бы к одной колонке, не являющейся разрезом указанным в group by, «забыли» применить групповую функцию выдаст ошибку.

Как работает group by можно прикинуть в экселе. Запишите данные на лист, отсортируйте по тем полям, которые должны быть в group by . Читая отсортированные данные подряд в любом случае когда значение в очередной строке в колонках, указанных в group by отличается от значений в предыдущей — вставьте новую строку, скопируйте значения колонок group by , а в остальные поместите формулы вроде СУММ() ячеек группы под которой подводится итог. Результат group by — это именно эти вставленные итоговые записи. СУБД работает примерно по такому же алгоритму — сначала сортирует, потом суммирует идущие подряд одинаковые записи.

Добавлю про MySQL — он все таки слишком вольно к этому относится. Старайтесь всегда явно применять групповые функции ко всем колонкам, что бы самому понимать что именно в них окажется, ибо ‘первое попавшееся’ ни чем не стандартизировано и может меняться от версии к версии и в зависимости от физического расположения записей на диске и плана выполнения запроса.

Источник

Sql GROUP BY и НЕ РАБОТАЕТ

У меня есть этот SQL-запрос, который дает мне результат, который не является полным (половина результата). Я хочу получить информацию о всех учениках из того же класса, который находится из таблицы учеников, а затем группировать их по классу.

Это код запросов:

В последнем запросе также отображается только одна информация, которая является первым именем студента класса «jss1» в таблице, но на этот раз показывает, что в jss1 есть 17 учеников, которые находятся в jss1

Как я могу манипулировать запросом, чтобы отображать все имена студентов в одном классе?

Это структура таблицы:

GROUP BY применяется, когда вы хотите сгруппировать некоторую информацию об агрегатных функциях (в качестве последнего запроса, в котором вы хотите узнать COUNT).

Итак, когда у вас есть сводная функция, и если вы хотите показать с ней скалярные поля, они должны быть помещены в предложение GROUP BY .

Предложение HAVING используется для применения условия агрегированного значения (например, я хочу знать все строки с COUNT > 1), напишу: HAVING COUNT() > 1 , поэтому все ваши запросы должны использовать WHERE

НЕПРАВИЛЬНО

СТАНОВИТСЯ

НЕПРАВИЛЬНО

СТАНОВИТСЯ

НЕПРАВИЛЬНО

СТАНОВИТСЯ

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

Запросить список учеников в каждом классе

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

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

обратите внимание, что использование group by в вышеуказанном запросе не требуется, вы можете легко получить результаты, используя предложение where , как это сделано в первом запросе.

Запросы, которые вы написали, не имеют смысла и не будут разбираться в каких-либо других СУБД, о которых я знаю. MySQL расширяет стандартное использование SQL GROUP BY, чтобы список выбора мог ссылаться на неагрегированные столбцы, не названные в предложении GROUP BY., который может будь то благословение и проклятие.

Чтобы помочь, рассмотрите следующие примеры данных

Теперь, в вашем первом запросе (скорректированном с учетом данных выше)

Нам нужно сначала подумать о логическом порядке операций выше:

Итак, первое, на что нужно обратить внимание, это группа, так как class — это столбец группировки, который вы хотите вернуть по одной строке для каждой группы, так что у вас будет:

В заключении оговорки теперь указано, что он должен быть A, оставляя:

Теперь это причина, по которой большинство СУБД сбой, на данный момент вам нужно SELECT first_name , НО, у вас есть два доступных значения ( «Тест 1» и «Тест 2» ), но только один чтобы заполнить, и дали двигателю никаких инструкций, из которых один из двух выбрать. В документации указано, что движок свободен в выборе любого доступного значения, и этот порядок не повлияет на него, поэтому вы можете различаться для одного и того же запроса в зависимости от плана выполнения.

Пока вы не уверены в GROUP BY , я бы рекомендовал вам включить ONLY_FULL_GROUP_BY .

Вот почему вы получаете только одну строку, а не все ученики. Ответ о том, как получить всех учеников, довольно простой, просто используйте WHERE :

Если вам нужен одинаковый формат одной строки для каждого класса, но все учащиеся перечислены, то вам может понадобиться GROUP_CONCAT :

Наконец, вы должны иметь USING только с агрегатными функциями. Примером этого может быть попытка найти классы с 2 студентами в:

Источник

Некорректно работает GROUP BY во VIEW MYSQl. Лыжи не едут?

Имеем:
таблица со статусами лидов lsu ,допустим

Имеем VIEW lsu_desc, которая нам делает DESC
что нибудь типо

SELECT * FROM lsu ORDER by `update` DESC

Делаем еще один VIEW lsu_grouped чтобы получать последний статус

SELECT * FROM lsu_desc GROUP by `lead_id`

И на выходе не получаем,блин,последний статус. Получаем почему то первый
В то же время запрос

SELECT * FROM(SELECT * FROM lsu ORDER by `update` DESC) as inv GROUP by `lead_id`

работает корректно.
КАК ЖЕ ТАК ТО блин.

проект большой, тут не пишу всех join которые в реальных запросах
Мне нужны view для сущностей типо lead, чтобы не писать каждый раз в контроллерах запросы.

Что с mysql не так? Почему такая обработка из представления, а главное- что делать?
И именно когда из VIEW подтягиваешь. Если делать SELECT FROM SELECT таких проблем нет(
Прувы

  • Вопрос задан более трёх лет назад
  • 53 просмотра

Спасибо хабру,нашел(
Если в определении представления есть конструкция ORDER BY, то она будет работать только в случае отсутствия во внешнем операторе SELECT, обращающемся к представлению, собственного условия сортировки. При наличии конструкции ORDER BY во внешнем операторе сортировка, имеющаяся в определении представления, будет проигнорирована.

Тем не менее,какой механизм реализации посоветовали бы? Тригер на апдейт статуса в основной таблице?

Источник

MySQL: выбор ALL с GROUP BY не работает [дубликат]

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

Выражение 0.1 + 0.2 === 0.3 возвращает false в JavaScript, но, к счастью, целочисленная арифметика в плавающей запятой является точной, поэтому ошибки с десятичным представлением можно избежать путем масштабирования.

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

18 ответов

Решение 1: удалить ONLY_FULL_GROUP_BY из консоли mysql

, вы можете прочитать здесь здесь

Решение 2: Удалить ONLY_FULL_GROUP_BY из phpmyadmin

  • Открыть phpmyadmin & amp; выберите localhost
  • Нажмите меню Переменные & amp; прокрутите вниз для режима sql
  • Нажмите кнопку редактирования, чтобы изменить значения & amp; удалите ONLY_FULL_GROUP_BY & amp; нажмите «Сохранить».

В MySQL 5.7 и Ubuntu 16.04 отредактируйте файл mysql.cnf.

Включите sql_mode следующим образом и сохраните файл.

Обратите внимание, что , в моем случае я удалил режим STRICT_TRANS_TABLES и ONLY_FULL_GROUP_BY.

Сделав это, он сохранит конфигурацию режима навсегда. Иначе, если вы просто обновите @@ sql_mode через MySQL, потому что он перезагрузится при перезагрузке машины / службы.

После этого, чтобы модифицированная конфигурация приняла действие, перезапустите службу mysql:

Попробуйте получить доступ к mysql:

Если вы можете войти в систему и получить доступ к консоли MySQL, это нормально. Отлично!

Источник

Оцените статью