- Пользоваться пятью основными агрегатными функциями
- Объяснять разницу между
COUNT(*),COUNT(столбец)иCOUNT(DISTINCT столбец) - Сочетать агрегаты с
WHEREи знать, как на них влияетNULL
Учителю нужен не балл каждого ученика, а средний балл класса. Владелец магазина хочет знать общую сумму продаж, а не просматривать каждый заказ. Ответ на такие вопросы — не список строк, а одно число. В SQL такие числа вычисляют агрегатные функции.
Что такое агрегатная функция?
Функция, которая берёт значения из множества строк и вычисляет по ним один результат. Обычная функция (например, ROUND) работает с каждой строкой отдельно, а агрегатная — со всеми строками сразу.
| Функция | Что возвращает |
|---|---|
| COUNT(*) | количество строк |
| COUNT(x) | количество значений x, не равных NULL |
| SUM(x) | сумму значений |
| AVG(x) | среднее значение |
| MIN(x) | наименьшее значение |
| MAX(x) | наибольшее значение |
COUNT: подсчёт
У COUNT три формы. COUNT(*) считает все строки. COUNT(email) считает только строки, в которых email заполнен, — у двух учеников e-mail равен NULL, поэтому получается 10. COUNT(DISTINCT city) даёт число разных городов.
SELECT COUNT(*) AS students,
COUNT(email) AS with_email,
COUNT(DISTINCT city) AS cities
FROM students;▸ Ожидаемый результат
students | with_email | cities 12 | 10 | 7
SUM, AVG, MIN и MAX
В одном запросе можно написать несколько агрегатов сразу. Среднее часто получается длинной дробью (здесь 293,558), поэтому округлим его с помощью ROUND. Результат всегда — одна строка, ведь вся таблица подытоживается как одна группа.
SELECT SUM(stock) AS total_items,
ROUND(AVG(price), 2) AS avg_price,
MIN(price) AS cheapest,
MAX(price) AS most_expensive
FROM products;▸ Ожидаемый результат
total_items | avg_price | cheapest | most_expensive 1086 | 293.56 | 3.2 | 1450
MIN и MAX работают не только с числами, но и с текстом и датами. Для дат в формате YYYY-MM-DD MIN даёт самую раннюю дату, а MAX — самую позднюю.
SELECT MIN(order_date) AS first_order,
MAX(order_date) AS last_order
FROM orders;▸ Ожидаемый результат
first_order | last_order 2025-01-15 | 2025-07-07
Вычисления с агрегатами
Результат агрегата — обычное число, поэтому с ним можно производить вычисления. MAX(age) - MIN(age) даёт разницу между наибольшим и наименьшим возрастом. Чтобы найти процент учеников с e-mail, делим COUNT(email) на COUNT(*) и умножаем на 100. Осторожно: 100 * 10 / 12 — деление целых чисел, оно даёт 83; для точного результата пишем 100.0.
SELECT MAX(age) - MIN(age) AS age_range,
100 * COUNT(email) / COUNT(*) AS int_pct,
ROUND(100.0 * COUNT(email) / COUNT(*), 1) AS pct_with_email
FROM students;▸ Ожидаемый результат
age_range | int_pct | pct_with_email 3 | 83 | 83.3
int_pct потерял дробную часть из-за деления целых чисел.Агрегаты и WHERE
WHERE срабатывает до агрегата: сначала строки фильтруются, затем вычисление идёт только по оставшимся строкам. Ниже мы берём только зачисления на курс 1 (Algebra): 4 ученика, средний балл 87,3.
SELECT COUNT(*) AS enrollments,
ROUND(AVG(score), 1) AS avg_score,
MIN(score) AS min_score,
MAX(score) AS max_score
FROM enrollments
WHERE course_id = 1;▸ Ожидаемый результат
enrollments | avg_score | min_score | max_score 4 | 87.3 | 75 | 97
Какова общая стоимость всех товаров на складе?
Показать решениеСкрыть решение
price * stock.Внутри агрегата можно писать выражение:
SUM(price * stock).СУБД сначала вычисляет произведение для каждой строки, а затем складывает: 40260,6.
SELECT SUM(price * stock) AS warehouse_value
FROM products;▸ Ожидаемый результат
warehouse_value 40260.6
SELECT AVG(age) AS avg_age
FROM students;▸ Ожидаемый результат
avg_age 15.5
Подведи итоги по курсу номер 1 (Algebra): число зачислений (students), средний балл, округлённый до 1 знака после запятой (avg_score), и лучший балл (best).
SELECT COUNT(*) AS students
-- add avg_score and best
FROM enrollments
WHERE course_id = 1;▸ Ожидаемый результат
students | avg_score | best 4 | 87.3 | 97
Для категории Electronics найди число товаров (products), общий остаток на складе (total_stock) и самую низкую цену (cheapest).
SELECT
-- three aggregates here
FROM products
WHERE category = 'Electronics';▸ Ожидаемый результат
products | total_stock | cheapest 4 | 63 | 120.5
Главное
- Агрегатная функция вычисляет один результат по множеству строк:
COUNT,SUM,AVG,MIN,MAX. COUNT(*)считает все строки,COUNT(x)— не равныеNULL, аCOUNT(DISTINCT x)— разные значения.WHEREвыполняется до агрегата, поэтому считаются только отфильтрованные строки.- Агрегаты (кроме
COUNT(*)) пропускают значенияNULL. - Не смешивай агрегат с обычным столбцом без
GROUP BY— в большинстве СУБД это ошибка.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.
students COUNT(*) даёт 12, а COUNT(email) — 10. Почему?