Группировка

Давайте взглянем на нашу таблицу телефонов и разобьем ее на группы по cityid, я специально поставил пробелы между группами:

+---------+-----------+-----------+-----------+--------+
| phoneid | firstname | lastname  | phone     | cityid |
+---------+-----------+-----------+-----------+--------+
|       1 | John      | Doe       | 4144122   |      1 |
|       2 | Steve     | Doe       | 414124    |      1 |

|       3 | Johnatan  | Something | 4142947   |      2 |
|       4 | Donald    | Trump     | 414251123 |      2 |
|       5 | Alice     | Cooper    | 414254234 |      2 |

|       6 | Michael   | Jackson   | 4142544   |      3 |
|       7 | John      | Abama     | 414254422 |      3 |
|       8 | Andre     | Jackson   | 414254422 |      3 |

|       9 | Mark      | Oh        | 414254422 |   NULL |
|      10 | Charly    | Lownoise  | 414254422 |   NULL |
|      12 | Mike      | NULL      | 1492823   |   NULL |
|      13 | Mike      | NULL      | 1492823   |   NULL |
+---------+-----------+-----------+-----------+--------+

Как найти количество записей для каждой из групп? Вот для этой задачи идеально подходит группировка – получить результат, сгруппировав его по определенной колонке:

SELECT CityId, count(*)
FROM phone
GROUP BY cityid;

Прочитаю, что я тут написал: выбрать id города и количество из таблицы телефонов, сгруппировав данные по cityid.

Сразу посмотрим на результат:

+--------+----------+
| CityId | count(*) |
+--------+----------+
|   NULL |        4 |
|      1 |        2 |
|      2 |        3 |
|      3 |        3 |
+--------+----------+

Как видите наш результате четко совпадает с тем, как мы разделили на группы нашу таблицу телефонов. Первая колонка – это id города, а вторая количество.

Слова GROUP BY должны идти в конце (только сортировка может идти после этого). После group by мы указываем, по какой колонке мы строим группы.

Тут очень важно понимать, что в SELECT мы можем указывать только колонки, по которым мы группируем или колонки, по которым мы считаем. В данном случае выводиться колонка cityid – по которой мы группируем и колонка с count. Можно также считать суммы по группе, минимум, максимум и т.д, то есть любые агрегатные функции.

Но мы не можем в SELECT указывать просто колонки, которые не участвуют в группе и не участвуют в агрегатной функции. Например:

SELECT CityId, FirstName, count(*)
FROM phone
GROUP BY cityid;

Такой запрос закончится ошибкой, потому что мы разбиваем данные на группы по городу, но просим вывести также и имя. Серверу просто срывает крышу в такой момент – какое из имен вывести, ведь в Торонто (cityid = 1) аж два имени John и Steve. Какое из них? Мы должны как-то четко сказать, какое из них нужно выбирать.

Можно сказать, что выбирай максимальное имя MAX:

SELECT CityId, max(FirstName), count(*)
FROM phone
GROUP BY cityid;

Теперь с точки зрения правил все верно – мы выбираем только город, по которому группируем и агригатные функции. И да, если у тебя возник вопрос – можно ли выполнять MAX на строках – можно. Строки сортируются по алфавиту и будет взято имя, которое идет последним – максимальное.

+--------+----------------+----------+
| CityId | max(FirstName) | count(*) |
+--------+----------------+----------+
|   NULL | Mike           |        4 |
|      1 | Steve          |        2 |
|      2 | Johnatan       |        3 |
|      3 | Michael        |        3 |
+--------+----------------+----------+

Предыдущая глава

Агрегатные функции SQL

Следующая глава

SQL Создаем базу данных

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне