Заметки WEB-разработчика

Полезные материалы для web-разработки

Особенности group by в MySql

В этой статье рассмотрим особенности выражения group by в mysql

Особенности group by в MySql

Ключевое слово group by используется в операторе select для того, чтобы объединять повторяющиеся значения в группы. Ключевое слово group by должно следовать за выражением where и предшествовать order by.

К функциям группирования, используемых в выражении group by для объединения данных в группы относятсы avg, max ,min, sum, count

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

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

SELECT `user_id`, `post`, max(`time`) FROM `test_table` GROUP BY `user_id`;

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

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

create table test_table (user_id int, post varchar(255), `time` datetime);
insert into test_table values (1, 'post1', '2012-10-14 11:21:22'),(1, 'post2', '2012-11-12 18:53:26'),(1, 'post3', '2012-11-15 16:51:08');
SELECT * FROM test_table;

+---------+--------+---------------------+
| user_id | post   | time                |
+---------+--------+---------------------+
|       1 | post 1 | 2012-10-14 11:21:22 |
|       1 | post 2 | 2012-11-12 18:53:26 |
|       1 | post 3 | 2012-11-15 16:51:08 |
+---------+--------+---------------------+

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:08 |
+---------+--------+---------------------+

Замечание: Попытки повлиять на выбираемые строки с помощью сортировки эффекта не дадут, так как сортировка выполняется после группировки. Например:

SELECT * FROM `таблица` GROUP BY user_id ORDER BY `time` DESC;

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


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

Комментарии

Комментарии через Вконтакте