В таблице заказов часть значений суммы равна NULL: чем будет отличаться подсчёт строк от суммирования этого столбца?
NULL не считается нулём. COUNT(*) посчитает все строки, а COUNT(столбец) — только строки с известным значением. SUM(столбец) пропустит NULL; если все значения в группе равны NULL или строк для суммирования нет, результатом обычно будет NULL, а не ноль.
Агрегатные функции появились как средство сворачивания множества строк в итоговые показатели: количество, сумму, среднее или экстремальное значение. В реляционной модели NULL используется для обозначения отсутствующего или неизвестного значения, поэтому его нельзя автоматически трактовать как числовой ноль.
Такое различие позволяет отделить ситуацию нулевой суммы от ситуации, когда сумма неизвестна из-за отсутствующих данных. Цена этой выразительности — необходимость явно учитывать NULL в отчётах и бизнес-логике.
Предположим, в группе три заказа: со значениями 100, 50 и NULL. Количество строк равно трём, количество известных сумм — двум, а сумма известных значений — 150. Если заменить NULL на ноль без понимания смысла данных, можно скрыть проблему неполной загрузки или ошибочно заявить, что по заказу действительно не было суммы.
Особенно опасны отчёты, где COUNT(*), COUNT(сумма) и SUM(сумма) воспринимаются как показатели одного и того же набора данных. Они отвечают на разные вопросы: сколько строк существует, сколько значений известно и каков итог известных значений.
COUNT(*) считает строки после применения фильтров и не зависит от того, какие столбцы содержат NULL. COUNT(выражение) считает только те строки, где результат выражения не равен NULL.
Большинство агрегатов над выражением игнорирует NULL: SUM, AVG, MIN и MAX работают с оставшимися известными значениями. Поэтому AVG вычисляет среднее по известным значениям, а не распределяет пропуски как нули.
COALESCE в последнем выражении меняет представление результата: неизвестную или отсутствующую сумму отчёт начинает показывать как ноль. Это допустимо только тогда, когда по правилам предметной области отсутствие значения действительно означает нулевую величину.
Для группировки важно различать две ситуации: группа существует, но все её суммы NULL, и после фильтрации не осталось строк. В обеих ситуациях SUM обычно возвращает NULL, тогда как COUNT(*) возвращает соответственно число строк группы или ноль для результата без строк.
COUNT(DISTINCT столбец) также не учитывает NULL, но дополнительно удаляет дубликаты. Если пропуск нужно считать отдельной категорией, его сначала преобразуют в явное значение только на уровне отчётной логики, понимая последствия такого преобразования.
В отчёте по регионам требовалось показать число заказов и выручку. Часть старых заказов была загружена без суммы: NULL означал ошибку интеграции, а не бесплатный заказ.
Рассматривались два варианта. Использовать COALESCE(SUM(amount), 0) было удобно для графиков, но это скрывало регионы с полностью отсутствующими суммами. Считать только COUNT(amount) давало число заполненных сумм, но не показывало полный объём заказов.
Выбрали отдельные показатели: COUNT(*) для числа заказов, COUNT(amount) для контроля полноты и исходный SUM(amount) для выручки. Для визуализации дополнительно выводили признак неполноты данных, а ноль подставляли только в отдельном поле после проверки бизнес-смысла. В результате отчёт одновременно показывал финансовый итог и выявлял проблемы загрузки.
Что произойдёт со средним значением, если часть строк содержит NULL?
AVG игнорирует NULL и делит сумму известных значений на количество известных значений, а не на общее число строк. Поэтому замена пропусков на ноль перед усреднением обычно уменьшает результат и корректна только при подтверждённом смысле нуля.
Почему COUNT(*) и COUNT(столбец) могут давать разные результаты в одной группе?
COUNT(*) измеряет кардинальность группы после фильтрации: каждая оставшаяся строка считается. COUNT(столбец) измеряет число строк с ненулевым, то есть не NULL, значением указанного выражения. Разница между ними может использоваться как простой индикатор неполноты данных.
Как безопасно получить ноль вместо NULL у суммы?
Обычно применяют COALESCE(SUM(столбец), 0), но сначала нужно определить семантику пропуска. Если NULL означает отсутствие продаж, ноль может быть правильным; если он означает неизвестную сумму или ошибку загрузки, такое преобразование уничтожит важную информацию. Для группового отчёта также следует отличать отсутствие строк от существующей группы со всеми неизвестными значениями.