Все материалы
Продуктовая аналитикапрактикумсредний

NOT EXISTS и anti-join в SQL: как найти пользователей без события

Практический разбор NOT EXISTS и anti-join: пользователи без покупки, заказы без возврата и сегменты, которые не дошли до следующего шага.

КПКейсПрактика28 июля 2026 г.8 мин

Сегмент «не купили» нельзя получить простым подсчётом пользователей без строки в отчёте. После LEFT JOIN легко получить дубли, перепутать NULL с пустым значением или случайно превратить соединение в INNER JOIN фильтром в WHERE. Anti-join помогает выразить отрицательную связь явно. Разберём вопрос на одном запросе: Как корректно найти тех, у кого не произошло событие?

Сначала определим задачу

Как корректно найти тех, у кого не произошло событие?

Чтобы найти пользователей, зарегистрированных за неделю, но без activation в первые семь дней, ограничь и базовую когорту, и окно события. «Никогда не активировался» и «не активировался в первые семь дней» — разные условия. Большинство ошибок здесь методологические, а не синтаксические.

отсутствие события тоже нужно определить

Используй NOT EXISTS как основной читаемый способ отрицательной проверки. LEFT JOIN anti-join оставь для случаев, когда нужны поля второй таблицы или аудит совпадений. В любом варианте явно фиксируй окно и ключ связи.

Как работает конструкция

Anti-join возвращает строки левой таблицы, для которых не найдено совпадение в правой. В SQL это обычно NOT EXISTS или LEFT JOIN ... WHERE right.key IS NULL. Первый вариант прямо говорит о проверке отсутствия, второй удобен, если нужно показать поля и диагностировать связь.

Сначала сформируй левую базу и назови её зерно. Затем опиши, какая строка справа считается совпадением и в каком временном окне. Проверь пользователя с несколькими событиями, событием вне окна и NULL id.

  • Зафиксируй одну строку результата.
  • Отдели условия по исходным строкам от условий по рассчитанным значениям.
  • Назови период, ключи связи и правило для повторов.

Запрос по шагам

Названия таблиц здесь условные. При переносе сохрани зерно и бизнес-условия, а не буквальный синтаксис примера.

Когорта без покупки в первые 14 дней
SELECT u.user_id, u.channel
FROM users u
WHERE u.registered_at >= DATE '2026-07-01'
  AND u.registered_at < DATE '2026-07-08'
  AND NOT EXISTS (
    SELECT 1 FROM events e
    WHERE e.user_id = u.user_id AND e.event_name = 'purchase'
      AND e.occurred_at >= u.registered_at
      AND e.occurred_at < u.registered_at + INTERVAL '14 days'
  );

Проверка результата

Собери пять-десять строк, где ответ можно получить вручную. Добавь NULL, дубль, объект без связанной записи и значение на границе периода. Затем сравни число строк и уникальных ключей до и после спорного шага.

Выполненный без ошибки запрос ещё не является правильным. Другой аналитик должен суметь восстановить из него источник, фильтр, grain и ожидаемое поведение на крайних случаях.

Anti-join: что проверить
ЧастьВопросПример
левая базакто должен попасть?новые пользователи
совпадениекакое событие?purchase
окнодо какой даты?14 дней
ключкак связать?user_id

Границы и альтернативы

Условие правой таблицы в WHERE после LEFT JOIN превращает его в INNER JOIN. Проверка right.id IS NULL должна использовать настоящий not-null ключ. Не делай NOT EXISTS по всей истории, если вопрос про конкретную когорту или период.

Используй NOT EXISTS как основной читаемый способ отрицательной проверки. LEFT JOIN anti-join оставь для случаев, когда нужны поля второй таблицы или аудит совпадений. В любом варианте явно фиксируй окно и ключ связи.

Когорта после отрицательной проверки

Пользователь остаётся в базе, если совпадение не найдено в заданном окне.

Пользователи

Задание для самостоятельной проверки

Собери список новых пользователей без покупки в 14 дней. Затем разбей его по каналу и проверь, что сумма сегментов совпадает с общей базой. Добавь событие на 15-й день: оно не должно убрать пользователя из результата.

  • Сначала запиши ожидаемый результат словами.
  • Проверь запрос на маленькой контрольной выборке.
  • Объясни, что запрос считает и чего не доказывает.

Решение для команды

Используй NOT EXISTS как основной читаемый способ отрицательной проверки. LEFT JOIN anti-join оставь для случаев, когда нужны поля второй таблицы или аудит совпадений. В любом варианте явно фиксируй окно и ключ связи.

Продолжить чтение
Вся библиотека