Почему COUNT возвращает разные числа: NULL в SQL
Три строки в таблице не всегда означают три значения в колонке. Разберём разницу, которая влияет на отчёты и ответы на собеседовании.
Один набор данных
Представь три заказа. В колонке discount записаны значения 0, 10 и NULL. Ноль здесь означает известную скидку в ноль рублей. NULL — отсутствие известного значения. Это разные ситуации.
COUNT(*) → 3COUNT(discount) → 2COUNT(DISTINCT discount) → 2COUNT(*) считает строки. COUNT(discount) — строки с непустым, то есть не NULL, значением в этой колонке. DISTINCT оставляет уникальные известные значения: в нашем примере это 0 и 10.
Где появляется ошибка
Если назвать COUNT(discount) количеством заказов, отчёт потеряет третий заказ. Если заменить NULL на ноль без обсуждения смысла, мы заявим, что у третьего заказа скидки не было. Но исходные данные этого не говорят.
Аналитик сначала уточняет значение пропуска. Скидка неизвестна из-за ошибки загрузки? Поле не заполняется для части заказов? Или по правилам системы пропуск действительно означает отсутствие скидки? От этого зависит обработка.
Ещё один пример: среднее
AVG(discount) для этих значений даст 5: (0 + 10) / 2. Если сознательно заменить NULL на 0, среднее станет 10 / 3. Оба вычисления возможны, но отвечают на разные вопросы.
Как объяснить на собеседовании
- Назови, что считаешь: строки, известные значения или уникальные значения.
- Отдельно объясни поведение NULL.
- Покажи маленький пример, где результаты расходятся.
- Уточни бизнес-смысл пропуска, прежде чем выбирать обработку.
Проверь себя
Добавь ещё одну строку со скидкой 10. Теперь COUNT(*) равен 4, COUNT(discount) — 3, а COUNT(DISTINCT discount) по-прежнему 2. Попробуй объяснить каждое число своими словами.
Пример использует обычное поведение SQL-агрегатов, в частности PostgreSQL. Это авторский учебный материал, без привязки к конкретной компании.
Хочешь разобрать свою ситуацию вместе?
Написать Никите ↗