JavaRush /Курсы /SQL SELF /Влияние NULL на агрегатные функции: SUM(), COUNT(), AVG()...

Влияние NULL на агрегатные функции: SUM(), COUNT(), AVG(), MIN(), MAX()

SQL SELF
9 уровень , 2 лекция
Открыта

Вспоминаем, что агрегатные функции — это те, которые работают сразу с несколькими строками данных и возвращают один результат. В PostgreSQL вы часто будете использовать следующие агрегатные функции:

  • SUM() — суммирование данных.
  • AVG() — нахождение среднего значения.
  • MIN() — поиск минимального значения.
  • MAX() — поиск максимального значения.
  • COUNT() — подсчёт строк.

На первый взгляд, всё просто: передаёшь в функцию столбец или выражение, и получаешь результат. Но что происходит, если в столбце попадается NULL?

Поведение NULL в агрегатах: краткий обзор

Вот здесь начинается самое интересное:

  • SUM() и AVG() игнорируют NULL. Если хотя бы одна запись имеет значение NULL, она просто не учтется в вычислениях. Вроде бы справедливое поведение, ведь как вырастет сумма, если кто-то "не пришёл на вечеринку"? Или как считать среднее, если одного значения не хватает?
  • MIN() и MAX() также пропускают NULL. Они находят минимальное или максимальное значение только из тех данных, которые не являются NULL. Так что, когда вы ищете самого младшего сотрудника, пропустившего заполнение даты рождения, NULL не станет победителем.
  • COUNT(*) учитывает все строки, даже те, где есть NULL. А вот COUNT(column) будет считать только строки, где в указанном столбце есть значение, то есть NULL игнорируется.

Давайте разберем это на примерах.

Примеры использования агрегатных функций с NULL

Вот таблица students_scores, содержащая оценки студентов за тест:

student_id name score
1 Алиса 85
2 Боб NULL
3 Чарли 92
4 Дана NULL
5 Елена 74

Теперь зададим несколько запросов и разберём их результаты:

  1. Сумма всех оценок: SUM()
SELECT SUM(score) AS total_score
FROM students_scores;

Результат:

total_score
251

Как видите, пропущенные NULL значения просто не участвовали в суммировании. Для Алисы (85), Чарли (92) и Елены (74) сумма составила 251. Боб и Дана остались за бортом.

  1. Средняя оценка: AVG()
SELECT AVG(score) AS average_score
FROM students_scores;

Результат:

average_score
83.67

Опять же, NULL были проигнорированы, и среднее значение рассчитывалось только для тех, у кого есть оценки: (85 + 92 + 74) / 3 = 83.67.

  1. Минимальная и максимальная оценка: MIN() и MAX()
SELECT
    MIN(score) AS min_score, 
    MAX(score) AS max_score 
FROM students_scores;

Результат:

min_score max_score
74 92

Здесь тоже всё просто: NULL значения снова проигнорированы, и минимальной стала оценка 74, а максимальной — 92.

  1. Подсчёт строк: COUNT(*) vs COUNT(column)
SELECT
    COUNT(*) AS total_rows, 
    COUNT(score) AS non_null_scores 
FROM students_scores;

Результат:

total_rows non_null_scores
5 3
  • COUNT(*) учёл все строки, включая те, где score равен NULL.
  • COUNT(score) посчитал только те строки, у которых в столбце score есть значение.

Практические кейсы

Приведём несколько практических примеров.

Пример 1: Подсчёт сотрудников с указанной и неуказанной зарплатой

Допустим, у нас есть таблица employees с зарплатами.

id name salary
1 Alex Lin 50000
2 Maria Chi NULL
3 Anna Song 60000
4 Otto Art NULL
5 Liam Park 55000

Мы хотим узнать, сколько сотрудников указали свою зарплату, а сколько — нет.

SELECT
    COUNT(*) AS total_employees,
    COUNT(salary) AS employees_with_salary,
    COUNT(*) - COUNT(salary) AS employees_without_salary
FROM employees;

Здесь:

  • COUNT(*) вернёт общее количество сотрудников.
  • COUNT(salary) посчитает, сколько сотрудников указали зарплату.
  • Для вычисления числа сотрудников без зарплаты, мы просто вычитаем одно значение из другого.

Результат

total_employees employees_with_salary employees_without_salary
5 3 2

Пример 2: Расчёт средней цены товаров с учётом отсутствующих данных

Вы владелец волшебного магазина, и в таблице products есть колонка price, но у некоторых товаров цена пока не указана.

id name price
1 Magic Wand 150
2 Enchanted Cloak NULL
3 Potion Bottle 75
4 Spell Book 200
5 Crystal Ball NULL

Вам нужно узнать среднюю цену только для тех товаров, где она задана.

SELECT AVG(price) AS average_price
FROM products;

Результат:

average_price
141.6667

Если вы хотите указать цену по умолчанию для товаров без цены (например, сделать её равной 0), можно использовать функцию COALESCE() из следующей лекции.

Пример 3: Нахождение минимального и максимального возраста студентов

В таблице students хранится возраст учащихся, но для некоторых из них возраст неизвестен (NULL).

id name age
1 Alex Lin 20
2 Maria Chi NULL
3 Anna Song 19
4 Otto Art 22
5 Liam Park NULL

Мы хотим узнать, самого младшего и старшего студента.

SELECT
    MIN(age) AS youngest_student,
    MAX(age) AS eldest_student
FROM students;

Результат:

youngest_student eldest_student
19 22

Этот запрос вернёт минимальный и максимальный возраст только для тех студентов, чей возраст указан. NULL снова будет опущен.

Особенности и подводные камни

Когда работаете с NULL в агрегатах, важно помнить про следующие моменты:

  • В сумме SUM() и среднем AVG() NULL не учитываются. Это можно использовать, чтобы не добавлять "пустые" значения в вычисления.
  • Если вам нужно учитывать строки с NULL в столбце, можно использовать COUNT(*).
  • При использовании MIN() или MAX(), NULL не влияет на результат. Однако, если весь столбец заполнен только NULL, результатом будет тоже NULL.

Советы для работы с NULL

  1. Учитывайте специфику задачи. Важно понимать, нужно ли учитывать NULL в вашем запросе. Иногда, как в случае с AVG(), их игнорирование — это то, что нужно. А иногда, как при подсчёте общего количества, важно учесть и строки с NULL.
  2. Используйте COALESCE() при необходимости. Если нужно заменить NULL значением по умолчанию в расчётах, функция COALESCE() станет вашим другом (но это уже тема следующей лекции).
  3. Не путайте COUNT(*) и COUNT(column). Это классическая ошибка новичков. Первый считает строки, второй — только строки с ненулевыми значениями.

Теперь вы знаете, как хитро умалчивающий NULL может повлиять на агрегаты. Это знание позволит вам избежать неприятных сюрпризов и использовать NULL в своих интересах. В следующей лекции мы изучим мощный инструмент COALESCE(), чтобы справляться с NULL ещё эффективнее.

2
Задача
SQL SELF, 9 уровень, 2 лекция
Недоступна
Сумма и среднее значение оценок
Сумма и среднее значение оценок
2
Задача
SQL SELF, 9 уровень, 2 лекция
Недоступна
Подсчёт строк с заполненными и незаполненными данными
Подсчёт строк с заполненными и незаполненными данными
Комментарии (13)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Глеб Уровень 27
31 декабря 2025
Решение неверное в задаче для null_prices, вот такой запрос проходит: COUNT(CASE WHEN price IS NULL THEN 1 END) AS null_prices Но пришлось погуглить
Сергей Третяк Уровень 14
20 октября 2025
ну справился, здесь сборка получилась, где COALESCE использовал, а где тупо через where is not null пришлось сделать. Итог: в подсказке не соответствует запросу задачи, а по факту можно изголиться, чтобы было is null и is not null работали
Сергей Третяк Уровень 14
19 октября 2025
да ошибка в условиях, как написано у меня и в подсказке(первый раз использовал) автомат не принимает: Запрос должен корректно учитывать специфику работы с `NULL` значениями, используя операторы `IS NULL` и `IS NOT NULL`. Требуется явно использовать операторы! но один count(price) уже IS NOT NULL на автомате второй COUNT(*) - COUNT(price) не напишешь потому как нужно явно указать IS NULL; тупик
9 октября 2025
Через COUNT(*) - COUNT(price) AS null_prices не принимает. Пошел в правильное решение - там тоже самое. На всякий случай скопировал - не принимает верное решение. Походу валидатор AI и у него свое мнение, отличное от разработчиков 😃. Восстание машин не за горами!
Vadim Smirnov Уровень 10
13 января 2026
принимает
Programmista Programmista Уровень 14
29 июля 2025
во второй задачи еще нужно использовать кострукцию case... when.. then.. else .. end и функцию sum - этого нет в требованиях
Anemon Уровень 13 Expert
25 августа 2025
Нет, не надо. Тут, кстати, есть функция посмотреть ответ, если что. И ты увидишь что мы там используем только то что проходили. Не слушай ИИшку))0)0
Slevin Уровень 1
2 сентября 2025

 COUNT(*) - COUNT(price) AS null_prices
Евгений Уровень 49 Expert
22 июля 2025
Во второй задаче ошибка в услових: Запрос должен корректно учитывать специфику работы с `NULL` значениями, используя операторы `IS NULL` и `IS NOT NULL`. ключевые слова null там вообще не используются, и валидатор это принимает
Anemon Уровень 13 Expert
25 августа 2025
Тут прекольчик есть небольшой. Не знаю зачем они это написали, но суть в том что COUNT() будет считать всё что не NULL, а так как в голову приходит (по крайней мере мне) написать что-то типа COUNT(price IS NOT NULL), то COUNT будет считать всё что окажется внутри, ведь будь то TRUE или FALSE, это уже не NULL
Alexandr Уровень 16
2 июля 2025
SELECT COUNT(*) AS total_rows, COUNT(price) AS non_null_prices, SUM(CASE WHEN price IS NULL THEN 1 ELSE 0 END) AS null_prices FROM products;
Серега Батенин Уровень 12
24 июня 2025
В первой задаче копируешь названия колонок из условия а валидатор не принимает, якобы не правильно названы. Смотришь правильное решение, там те же самые названия, но решение принимает. Магия
23 июня 2025
Орфографические ошибки, не указывается подчеркивание