SQL-проверки уникальности и NULL: базовый контроль перед отчётом
Чеклист SQL-проверок для ключей, NULL, ссылочной целостности и пустых групп перед публикацией метрики или дашборда.
Содержание статьи
Большинство ошибок обнаруживается уже после публикации, когда кто-то замечает невозможную долю или исчезнувший сегмент. Небольшой набор проверок может поймать проблему раньше. Какие быстрые SQL-проверки стоит запускать до того, как цифра попадёт к руководителю?
Когда пригодится подход
Какие быстрые SQL-проверки стоит запускать до того, как цифра попадёт к руководителю?
Большинство ошибок обнаруживается уже после публикации, когда кто-то замечает невозможную долю или исчезнувший сегмент. Небольшой набор проверок может поймать проблему раньше.
Если user_id внезапно стал NULL у 18% событий, DAU может не измениться сразу, но сегментация и retention уже будут неполными.
Договорённости до расчёта
Проверяй и сырой grain, и grain витрины. Уникальность event_id не гарантирует уникальность user-day, а отсутствие NULL в справочнике не гарантирует отсутствие потерянных связей.
Для каждой метрики выпиши 3–5 инвариантов, посчитай их в отдельном запросе и зафиксируй порог тревоги. Проверка должна вернуть понятный результат, а не просто пустой набор.
Если показатель строится по событиям, отдельно проверь повторную отправку, идентичность пользователя и часовой пояс. Если данные приходят из бизнес-системы, сопоставь техническое поле с тем, как команда реально принимает решение.
вопрос → объект → период → расчёт → проверка → решениеЛюбой пропущенный шаг может изменить смысл итогового числа.
Пример с данными
Если user_id внезапно стал NULL у 18% событий, DAU может не измениться сразу, но сегментация и retention уже будут неполными.
Не копируй пример в рабочий отчёт вслепую. Сначала замени названия таблиц и полей, проверь кардинальность связей и запиши, какие строки должны попасть в результат. Хорошая адаптация сохраняет логику, но делает допущения видимыми.
| Ожидание | SQL-сигнал | Реакция |
|---|---|---|
| Ключ уникален | COUNT > COUNT DISTINCT | остановить витрину |
| user_id заполнен | NULL rate > threshold | проверить трекинг |
| Есть родитель | LEFT JOIN IS NULL | проверить загрузку |
SELECT COUNT(*) - COUNT(DISTINCT event_id) AS duplicate_rows, COUNT(*) FILTER (WHERE user_id IS NULL) AS missing_users, COUNT(*) FILTER (WHERE amount < 0) AS negative_amounts\nFROM events;Ограничения метода
Слишком широкие пороги создают шум, а слишком узкие маскируют сезонность. Не смешивай проверку структуры и проверку бизнес-смысла в один непонятный статус.
Отдельно протестируй пустой результат, NULL, дубль, граничную дату и объект без связанной записи. Эти случаи не являются редкими исключениями: именно они чаще всего превращают рабочий показатель в красивую, но неверную цифру.
- Не смешивай зрелые и незрелые периоды без отдельной подписи.
- Не заменяй проверку качества тем, что запрос просто выполнился.
- Не делай причинный вывод из одного разреза.
Сравнение на графике
График здесь нужен не для украшения статьи. Он помогает увидеть форму сигнала: тренд, разрыв между сегментами, хвост распределения или этап, на котором теряется объект. Сначала прочитай оси и единицы, затем сравни с таблицей и только после этого формулируй вывод.
На визуализации «Контроль качества по дням» сравнивай не только максимальное значение. Проверь, одинаковы ли базы, не скрыта ли неполная дата и не меняется ли знаменатель от категории к категории.
Условный пример: объём событий стабилен, но доля NULL внезапно растёт.
Самостоятельная проверка
Сделай четыре запроса: дубли ключа, NULL в обязательном поле, orphan events и резкий скачок объёма по дню. Запиши, кто получает alert и какое действие делает.
После упражнения напиши вывод в двух версиях. Первая — техническая: какие строки и условия дали результат. Вторая — для команды: что изменилось, насколько это надёжно и какое действие стоит проверить. Если эти версии противоречат друг другу, вернись к определению показателя.
- Собери контрольный пример из пяти-десяти строк.
- Сверь итог с независимым способом расчёта.
- Проверь хотя бы один крайний случай.
- Зафиксируй дату, версию схемы и ограничение.
Следующий шаг
Автоматизируй проверки, которые повторяются и имеют ясное ожидание. Оставь человеку проверки смысла: новая категория может быть не ошибкой, а реальным изменением продукта.
Сильный аналитический материал не обещает абсолютной уверенности. Он показывает, как получить число, где оно может ошибиться и какое решение можно принять уже сейчас. Такой формат хорошо переносится в дашборд, SQL-тренажёр, собеседование и рабочее обсуждение с командой.
Материалы по теме

SQL-проверки качества данных: дубли, пропуски и скачки метрик
Практический чеклист SQL-проверок перед дашбордом: найти дубли, пропущенные ключи, события без пользователей и неожиданные скачки дневного объёма.
COUNT(*) и COUNT(column) в SQL: почему NULL меняет количество
Разбираем разницу COUNT(*), COUNT(column) и COUNT DISTINCT на пропусках, пользователях и денежных фактах.

Операторы сравнения и логика в SQL: AND, OR, NOT и NULL
Трёхзначная логика SQL на практике: почему NOT IN возвращает пустоту, где AND незаметно съедает OR и как собрать длинный фильтр так, чтобы его можно было проверить.