AVG и ROUND в SQL: как посчитать среднее и не соврать себе
· 5 мин чтения СтатьяSQL

AVG и ROUND в SQL: как посчитать среднее и не соврать себе

Почему AVG молча пропускает пустые значения, как округлить результат до двух знаков, чем WHERE отличается от HAVING и когда нужен GROUP BY.

Запрос вида select round(avg(rating), 2) from reviews where device = 'tv' выглядит безобидно и почти всегда пишется правильно с первого раза. Проблема не в синтаксисе — в том, что среднее умеет врать тихо, и заметить это по результату нельзя.

AVG пропускает пустые значения

Главная ловушка одна: AVG не считает строки, где значение пустое (NULL). Он не подставляет ноль — он их просто не видит, и в знаменателе оказывается меньше строк, чем вы думали.

Разница получается заметной. Если из ста отзывов оценку поставили сорок, AVG(rating) вернёт среднее по этим сорока. Формально верно, а по смыслу — «средняя оценка тех, кто вообще оценивал», и это совсем другое утверждение.

Поэтому среднее полезно смотреть рядом с двумя числами: сколько строк всего и по скольким считали.

SELECT COUNT(*)      AS всего,
       COUNT(rating) AS с_оценкой,
       ROUND(AVG(rating), 2) AS среднее
FROM reviews
WHERE device = 'tv';

COUNT(*) считает все строки, COUNT(rating) — только заполненные. Разошлись — значит среднее посчитано не по всем, и это надо знать до того, как показывать цифру кому-то ещё.

ROUND: второй аргумент — знаки после запятой

ROUND(x, 2) оставляет два знака, ROUND(x) округляет до целого. Округлять стоит в самом конце: если сначала округлить каждое значение, а потом усреднить, ошибка накопится.

И округление — это оформление, а не расчёт. Внутри отчёта храните полное число, а ROUND ставьте на последнем шаге, там, где результат попадает человеку на глаза.

GROUP BY: среднее по каждой группе

Запрос выше даёт одно число на весь телевизор. Чтобы получить среднее по каждому виду устройств сразу, нужен GROUP BY:

SELECT device,
       COUNT(*) AS отзывов,
       ROUND(AVG(rating), 2) AS среднее
FROM reviews
GROUP BY device
ORDER BY среднее DESC;

Правило простое: всё, что стоит в SELECT и не завёрнуто в COUNT, AVG или другую считающую функцию, обязано стоять и в GROUP BY. Иначе база либо откажется выполнять запрос, либо — что хуже — выдаст произвольную строку из группы.

WHERE или HAVING

Эти два слова путают чаще всего, а разница у них честная и запоминается с одного раза.

  • WHERE отсеивает строки до группировки: «берём только телевизоры».
  • HAVING отсеивает группы после подсчёта: «оставляем те, где отзывов больше десяти».

Написать WHERE COUNT(*) > 10 нельзя: на этом шаге считать ещё нечего, группы не собраны. Нужно HAVING COUNT(*) > 10.

Ещё одна тихая ловушка: среднее по среднему

Средние нельзя усреднять. Если у одного устройства 3 отзыва со средним 5, а у другого 300 со средним 4, то среднее по этим двум числам — 4,5, а настоящее среднее по всем отзывам — 4,01. Считать нужно всегда от исходных строк, а не от готовых результатов.

Где потренироваться

Всё это проверяется руками за один вечер. В тренажёре SQL запросы выполняются на учебной базе и сверяются с эталоном — ошибку видно сразу, а не через полчаса. Первые уроки курса «SQL» открыты без регистрации: отбор строк через WHERE и сортировка и ограничение.

Если хочется сразу задач «как в жизни» — есть расследования: там базу приходится расспрашивать, чтобы понять, что произошло. А типовые вопросы работодателей собраны в статье вопросы по SQL на собеседовании.

Тренажёр SQL Запросы с проверкой на учебной базе — прямо в браузере, без установки.
Открыть тренажёр

Ещё в блоге

Новый курсДетям Курс Scratch переписан заново — двенадцать уроков и настоящая сцена в браузере Курс Scratch написан заново: двенадцать уроков, домашняя работа к каждому, контрольная и мастерская блоков прямо на странице — сцена, палитра и поле сборки. · 3 мин чтения Новый курсПлатформа Курс SQL переписан заново — восемнадцать уроков и настоящая база в браузере Курс SQL переписан целиком: восемнадцать уроков, домашняя работа к каждому, контрольная и три подачи — для аналитика, разработчика и тестировщика. · 5 мин чтения СтатьяPython Цикл for и range в Python: как посчитать числа по условию Почему range(10, 31) не включает 31, чем % отличается от //, как работает счётчик count += 1 и где в такой задаче обычно теряют ответ. · 4 мин чтения Новый курсПлатформа «1С: запросы и отчёты» переписан заново — восемнадцать уроков с нуля Курс о запросах 1С и компоновке переписан целиком: восемнадцать уроков, домашняя работа к каждому, контрольная и три подачи под разную работу. · 4 мин чтения