Агрегатные функции в SQL
- Агрегатные функции используются подобно именам полей в операторе SELECT, но с одним исключением: они берут имя поля как аргумент. С функциями SUM и AVG могут использоваться только числовые поля. С функциями COUNT, MAX и MIN могут использоваться как числовые, так и символьные поля. При использовании с символьными полями MAX и MIN будут транслировать их в эквивалент ASCII кода и обрабатывать в алфавитном порядке. Некоторые СУБД позволяют использовать вложенные агрегаты, но это является отклонением от стандарта ANSI со всеми вытекающими отсюда последствиями.
Пример:
Например, можно вычислить количество студентов, сдававших экзамены по каждой дисциплине. Для этого надо выполнить запрос с группировкой по полю «Дисциплина» и вывести в качестве результата название дисциплины и количество строк в группе по данной дисциплине. Применение символа * в качестве аргумента функции COUNT означает подсчет всех строк в группе.
SELECT R1. Дисциплина, COUNT(*)
FROM R1
GROUP BY R1.Дисциплина;
Результат:
Если требуется сосчитать количество сдавших экзамен по какой-либо дисциплине, то необходимо исключить неопределенные значения из исходного отношения перед группировкой. В этом случае запрос будет выглядеть следующим образом:
SELECT R1.Дисциплина, COUNT (*)
FROM R1
WHERE R1. Оценка IS NOT NULL
GROUP BY R1.Дисциплина;
Результат:
не попадет в набор кортежей перед группировкой, поэтому количество кортежей в группе для дисциплины «Теория информации» будет на 1 меньше.
Аналогичный результат можно получить, если записать запрос следующим способом:
SELECT R1. Дисциплина, COUNT(R1. Оценка)
FROM R1
GROUP BY R1. Дисциплина;
Функция COUNT (ИМЯ АТРИБУТА) считает количество определенных значений в группе, в отличие от функции COUNT(*), которая считает количество строк в группе. Действительно, в группе с дисциплиной «Теория информации» будет 4 строки, но только 3 определенных значения атрибута «Оценка».
Правила обработки значений NULL в агрегатных функциях
Если какие-либо значения в столбце равны NULL при вычислении результата функции они исключаются.
Если все значения в столбце равны NULL , то Max Min Sum Avg = NULL , count = 0 (ноль).
Если таблица пуста, count(*) = 0 .
Можно применять агрегатные функции также и без операции предварительной группировки, в этом случае все отношение рассматривается как одна группа и для этой группы можно вычислить одно значение на группу.
Правила интерпретации агрегатных функций
Агрегатные функции могут быть включены в список вывода и тогда они применяются ко всей таблице.
SELECT MAX (Оценка) from R1 даст максимальную оценку на сессии;
SELECT SUM (Оценка) from R1 даст сумму всех оценок на сеcси;
SELECT AVG(Оценка) from R1 даст среднюю оценку по всей сессии.
2; Результат: " width="640"
Обратившись снова к базе данных «Сессия» (таблицы R1), найдем количество успешно сданных экзаменов:
SELECT COUNT(*) As Сдано _ экзаменов
FROM R1
WHERE Оценка 2;
Результат:
Аргументом агрегатных функций могут быть отдельные столбцы таблиц. Для того, чтобы вычислить, например, количество различных значений некоторого столбца в группе, необходимо применить ключевое слово DISTINCT совместно с именем столбца. Вычислим количество различных оценок, полученных по каждой дисциплине:
SELECT R1.Дисциплина, COUNT (DISTINCT R1.Оценка)
FROM R1
WHERE R1. Оценка IS NOT NULL
GROUP BY R1.Дисциплина;
Результат:
Тот же самый результат получается, если исключить явное условие в части WHERE, в этом случае запрос будет им следующий вид:
SELECT R1. Дисциплина, COUNT(DISTINCT R1. Оценка)
FROM R1
GROUP BY R1. Дисциплина;
Функция COUNT (DISTINCT R1.Оценка) считает только определенные различные значения.
Для того чтобы и в этом случае был получен нужный результат, необходимо сделать предварительное преобразование типа данных столбца «Оценка», приведя его к действительному типу, тогда и результат вычисления среднего не будет целым числом. В этом случае запрос будет выглядеть следующим образом:
2 Group by R2. Группа, R1. Дисциплина; Здесь функция CAST() выполняет преобразование столбца «Оценка» к действительному типу данных. " width="640"
Select R2.Группа, R1.Дисциплина,Count(*) as Всего, AVG(cast(Оценка as decimal(3,1))) as Средний_балл
From R1,R2
where R1. ФИО = R2. ФИО and R1. оценка is not null
and R1. Оценка 2
Group by R2. Группа, R1. Дисциплина;
Здесь функция CAST() выполняет преобразование столбца «Оценка» к действительному типу данных.
Нельзя использовать агрегатные функции в предложении WHERE, потому что условия в этом разделе оцениваются в терминах одиночной строки, а агрегатные функции — в терминах групп строк.
Предложение GROUP BY позволяет определять подмножество значений в особом поле в терминах другого поля и применять функцию агрегата к подмножеству. Это дает возможность объединять поля и агрегатные функции в едином предложении SELECT. Агрегатные функции могут применяться как в выражении вывода результатов строки SELECT, так и в выражении условия обработки сформированных групп HAVING. В этом случае каждая агрегатная функция вычисляется для каждой выделенной группы. Значения, полученные при вычислении агрегатных функций, могут быть использованы для вывода соответствующих результатов или для условия отбора групп.
Построим запрос, который выводит группы, в которых по одной дисциплине на экзаменах получено больше одной двойки:
1; Результат: " width="640"
SELECT R2. Группа
FROM R1,R2
WHERE R1. ФИО = R2. ФИО AND
R1.Оценка = 2
GROUP BY R2.Группа, R1.Дисциплина
HAVING count(*) 1;
Результат:
Пример: имеем БД «Банк», состоящую из одной таблицы F, в которой хранится отношение F, содержащее информацию о счетах в филиалах некоторого банка:
F = ;
Q = ;
Найти суммарный остаток на счетах в филиалах. Можно сделать раздельный запрос для каждого из них, выбрав SUM (Остаток) из таблицы для каждого филиала, но операция группировки GROUP BY, позволит поместить их все в одну команду:
SELECT Филиал , SUM( Остаток )
FROM F
GROUP BY Филиал;
GROUP BY применяет агрегатные функции независимо для каждой группы, определяемой с помощью значения поля Филиал. Группа состоит из строк с одинаковым значением поля Филиал, и функция SUM применяется отдельно для каждой такой группы, т. е. суммарный остаток на счетах подсчитывается отдельно для каждого филиала. Значение поля, к которому применяется GROUP BY , имеет по определению только одно значение на группу вывода, как и результат работы агрегатной функции.
5 000; Аргументы в предложении HAVING подчиняются тем же самым правилам, что и в предложении SELECT , где используется GROUP BY . Они должны иметь одно значение на группу вывода. " width="640"
Предположим, что выбрать только те филиалы, суммарные значения остатков на счетах которых превышают $5 000, а также суммарные остатки для выбранных филиалов. Чтобы вывести в результат филиалы, суммарные остатки в которых свыше $5 000, необходимо использовать предложение HAVING. Предложение HAVING определяет критерии, используемые, чтобы удалять определенные группы из вывода, точно так же, как предложение WHERE делает это для индивидуальных строк.
Правильной командой будет следующая:
SELECT Филиал, SUM(Остаток)
FROM F
GROUP BY Филиал
HAVING SUM ( Остаток ) 5 000;
Аргументы в предложении HAVING подчиняются тем же самым правилам, что и в предложении SELECT , где используется GROUP BY . Они должны иметь одно значение на группу вывода.
Следующая команда будет запрещена:
SELECT Филиал,SUM(Остаток)
FROM F
GROUP BY Филиал
HAVING ДатаОткрытия = 27/12/2004 ;
Поле ДатаОткрытия не может быть использовано в предложении HAVING , потому что оно может иметь больше, чем одно значение на группу вывода. Чтобы избежать такой ситуации, предложение HAVING должно ссылаться только на агрегаты и поля, выбранные GROUP BY . Имеется правильный способ сделать вышеупомянутый запрос:
SELECT Филиал,SUM(Остаток)
FROM F
WHERE ДатаОткрытия = ’27/12/2004’
GROUP BY Филиал;
Смысл данного запроса следующий: найти сумму остатков по каждому филиалу счетов, открытых 27 декабря 2004 года.
Как говорилось ранее, HAVING может использовать только аргументы, которые имеют одно значение на группу вывода. Практически ссылки на агрегатные функции — наиболее общие, но и поля, выбранные с помощью GROUP BY, также допустимы. Например, мы хотим увидеть суммарные остатки на счетах филиалов в Санкт-Петербурге, Пскове и Урюпинске:
SELECT Филиал, SUM(Остаток)
FROM F,Q
WHERE F. Филиал = Q. Филиал
GROUP BY Филиал
HAVING Филиал IN (‘Санкт-Петербург’, ‘Псков’, ‘Урюпинск’);
100 000; Если суммарный остаток более чем $100 000, то мы его увидим в результирующем отношении, в противном случае мы получим пустое отношение. " width="640"
Поэтому в арифметических выражениях предикатов, входящих в условие выборки раздела HAVING, прямо можно использовать только спецификации столбцов, указанных в качестве столбцов группирования в разделе GROUP BY. Остальные столбцы можно специфицировать только внутри спецификаций агрегатных функций COUNT, SUM, AVG, MIN и MAX, вычисляющих в данном случае некоторое агрегатное значение для всей группы строк. Результатом выполнения раздела HAVING является сгруппированная таблица, содержащая только те группы строк, для которых результат вычисления условия отбора в части HAVING есть TRUE. В частности, если раздел HAVING присутствует в запросе, не содержащем GROUP BY, то результатом его выполнения будет либо пустая таблица, либо результат выполнения предыдущих разделов табличного выражения, рассматриваемый как одна группа без столбцов группирования. Рассмотрим пример. Допустим, мы хотим вывести общую сумму остатков по всем филиалам, но только в том случае, если она более $100 000. В этом случае наш запрос не будет содержать операции группировки, но будет содержать раздел HAVING и будет выглядеть следующим образом:
SELECT SUM( Остаток )
FROM F
HAVING SUM( Остаток ) 100 000;
Если суммарный остаток более чем $100 000, то мы его увидим в результирующем отношении, в противном случае мы получим пустое отношение.
При использовании агрегатных функций необходимо помнить, что в результирующем наборе могут присутствовать только значения полей группировки и возможно значения агрегатных функций. Не допустимо группировать по одним значениям, а выводить другие значения. Это будет синтаксической ошибкой.