Разбиение на группы
Далее мы рассмотрим разбиение записей на группы и применение к группам агрегирующих функций. Такого рода приемы используются для подсчета количества писем от каждого автора. Запрос SELECT name from message ORDER BY name вернет нам всех авторов, каждый автор будет повторяться столько раз, сколько писем он написал. Сгруппируем записи по авторам: SELECT name from message GROUP BY name ORDER BY name. Вы видите, что повторов теперь нет. Записи разбиты на группы, и теперь, если автор повторялся несколько раз, эти несколько записей объединены в одну группу. При использовании агрегирующих функций с GROUP BY они применяются не ко всем записям, а к каждой группе. Например: SELECT name, COUNT(*) from message GROUP BY name ORDER BY name возвращает таблицу из двух столбцов, в первом - имя автора, во втором - количество сообщений, которое он написал.
Группировать можно по нескольким полям. В предыдущем запросе мы получили информацию по всем сообщениям, не различая их по гостевым книгам. Если мы хотим получить количество сообщений по каждому автору в каждой гостевой книге, то запрос будет выглядеть так: SELECT name, gb_id, COUNT(*) from message GROUP BY name, gb_id ORDER BY name. Сначала происходит разбиение записей на группы (name, gb_id), затем по каждой группе подсчитывается количество записей в ней.
Если мы захотим получить рейтинг авторов по гостевым книгам, кто написал наибольшее количество сообщений, то надо поставить сортировку по третьему столбцу в обратном порядке: SELECT name, gb_id, COUNT(*) from message GROUP BY name, gb_id ORDER BY 3 DESC.
На записи, попадающие в группы, можно накладывать условия отбора. Делается это отдельным оператором HAVING. Оператор WHERE нам не может помочь, т.к. он действует на все записи. Сначала из таблицы выбираются записи, удовлетворяющие условию WHERE, затем происходит разбиение на группы, вычисляются агрегирующие функции и выполняется оператор HAVING для каждой группы отдельно, который отсеивает лишние строки. Оператор HAVING может обрабатывать те же условия, что и оператор WHERE, но в нем можно использовать агрегирующие функции, т.к. их значение при выполнении оператора HAVING уже известно. Рассмотрим еще раз пример с авторами и количеством писем, которое они написали: SELECT name, COUNT(*) from message GROUP BY name ORDER BY name. Как вы помните, большинство авторов написало по одному письму. Допустим, такие авторы нас не интересуют, мы хотим посмотреть авторов, которые пишут в наши гостевые книги регулярно. Для этого модифицируем запрос следующим образом: SELECT name, COUNT(*) from message GROUP BY name HAVING COUNT(*)>2 ORDER BY name.