Группировка строк (предложение GROUP BY)
В SQL есть возможность разбивать любую таблицу на логические группы и вычислять агрегатные функции не для всей таблицы, а для каждой из этих групп. Для этого и служит предложение GROUP BY.
Синтаксис:
GROUP BY <столбец группировки1>[<, столбец группировки2>][,…]
Пример 35а. Посчитать общую длительность всех вызовов.
SELECT SUM(DLIT)
FROM VYZOVY
Пример 35б. Посчитать общую длительность всех исходящих вызовов (TIP_ID=2).
SELECT SUM(DLIT)
FROM VYZOVY
WHERE TIP_ID=2
Пример 35в. Посчитать общую длительность вызовов каждого типа.
вариант 1 (известны коды)
SELECT TIP_ID, SUM(DLIT)
FROM VYZOVY
GROUP BY TIP_ID
вариант 2 (известны названия)
SELECT T.NAZV, SUM(DLIT)
FROM VYZOVY V, TIPY_VYZ T
WHERE V.TIP_ID=T.ID
GROUP BY T.ID, T.NAZV
Предложение GROUP BY реализуется следующим образом:
- строки исходной таблицы, содержащие одинаковые значения столбца (столбцов) группировки, выделяются в отдельные группы (также создается отдельная группа для строк, в которых в столбце группировки присутствует NULL);
- для каждой созданной группы формируется одна строка в таблице результатов запроса, т.о. агрегатные функции вычисляются для каждой группы строк.
Ограничения на запросы с группировкой:
- в качестве столбцов группировки можно использовать только имена столбцов таблиц;
- возвращаемые столбцы в предложении SELECT должны иметь одно значение для каждой группы (это значит, что в качестве возвращаемых столбцов можно использовать агрегатные функции, столбцы группировки, константы, а также выражения, состоящие из перечисленных элементов).
На практике в предложении SELECT запроса с группировкой всегда входят столбец группировки и агрегатная функция. Если агрегатная функция не указана, значит, запрос можно написать без использования предложения GROUP BY (используя ключевое слово DISTINCT). И наоборот, если не включить в результаты запросов столбец группировки, невозможно будет определить, к какой группе относится каждая строка результатов.
Примечание 1. Все столбцы из предложения SELECT, в которых не используются агрегатные функции, должны быть обязательно указаны в предложении GROUP BY!!!
Примечание 2. Группировку лучше осуществлять по первичному ключу.
Пример 36. Вывести количество номеров определенного контакта.
SELECT COUNT(*)
FROM KONTAKTY K, NOMERA N
WHERE (K.ID=N.KONT_ID) AND (K.NAME1='Иванов Александр Сергеевич')
Пример 37. Вывести количество номеров для каждого контакта.
SELECT K.NAME1, COUNT(*)
FROM KONTAKTY K, NOMERA N
WHERE (K.ID=N.KONT_ID)
GROUP BY K.ID, K.NAME1
Пример 38. Вывести количество контактов в каждой группе.
SELECT G.NAZV, COUNT(*)
FROM GRUPPY G, KONT_GR KG
WHERE (G.ID=KG.GR_ID)
GROUP BY G.ID, G.NAZV
Пример 39. Вычислить, со сколькими контактами был зафиксирован каждый тип вызова.
Неправильно (вычисляется количество вызовов, а не количество контактов):
SELECT T.NAZV, COUNT(N.KONT_ID)
FROM TIPY_VYZ T, VYZOVY V, NOMERA N
WHERE (T.ID=V.TIP_ID) AND (V.NOMER_ID=N.ID)
GROUP BY T.ID, T.NAZV
Не работает в Microsoft Access:
SELECT T.NAZV, COUNT(DISTINCT N.KONT_ID)
FROM TIPY_VYZ T, VYZOVY V, NOMERA N
WHERE (T.ID=V.TIP_ID) AND (V.NOMER_ID=N.ID)
GROUP BY T.ID, T.NAZV
Работает в Microsoft Access:
SELECT T1.NAZV, COUNT(T1.KONT_ID)
FROM (SELECT DISTINCT T.NAZV, N.KONT_ID
FROM TIPY_VYZ T, VYZOVY V, NOMERA N
WHERE (T.ID=V.TIP_ID) AND (V.NOMER_ID=N.ID)) AS T1
GROUP BY T1.NAZV
Пример 40. Для каждого контакта вывести дату и время самого первого вызова каждого типа.
SELECT K.NAME1, T.NAZV, MIN(VREMYA) AS FIRST
FROM KONTAKTY K, NOMERA N, VYZOVY V, TIPY_VYZ T
WHERE (T.ID=V.TIP_ID) AND (V.NOMER_ID=N.ID) AND (N.KONT_ID=K.ID)
GROUP BY K.ID, K.NAME1, T.NAZV