Короткий ответ
Нужно сделать LEFT JOIN от полного списка дат периода (сгенерированного или из отдельной календарной таблицы) к агрегированным по дням данным и отобрать те даты, где после соединения не нашлось ни одной строки событий (COUNT(event) = 0 или event_id IS NULL).
Как это работает подробнее
если просто сделать SELECT DISTINCT date FROM events, пропущенные дни физически отсутствуют в данных и их невозможно «увидеть» — нужна внешняя точка отсчёта (полный список ожидаемых дат), от которой можно оттолкнуться через LEFT JOIN, чтобы явно выявить даты без единой строки в основной таблице.
Пример кода
question-66.sql
WITH days AS (
SELECT generate_series('2024-03-01'::date, '2024-03-31'::date, interval '1 day')::date AS day
),
agg AS (
SELECT DATE_TRUNC('day', event_time)::date AS day, COUNT(*) AS events_cnt
FROM events GROUP BY 1
)
SELECT d.day
FROM days d
LEFT JOIN agg a ON a.day = d.day
WHERE a.day IS NULL;Что использовать на практике
- Практика. такую проверку целесообразно делать частью регулярного мониторинга качества данных (data quality) — например, ежедневная автоматическая проверка «за последние 24 часа данные точно поступили» помогает поймать сбой в пайплайне до того, как искажённый отчёт увидит бизнес.
- Проверка. Проверка: для каждой найденной «пустой» даты проверить логи загрузки данных (ETL) за этот день, чтобы подтвердить техническую причину, а не бизнес-факт.
Подводные камни
- Частая ошибка. путают «день без единого события» (возможный сбой загрузки данных) с «днём с нулевой активностью пользователей» (легитимный бизнес-факт, например, выходной для B2B-продукта) — расследование должно отличать эти два случая по контексту, а не автоматически считать любой пропуск ошибкой.