← все задачи

SQL · задача 6 из 10

Дни без продаж

Средний 15 минут generate_seriesLEFT JOINCOALESCE

Условие

Нужен отчёт по продажам за сентябрь, где есть строка на каждый день месяца, включая дни без единой продажи — с нулём.

Что требуется

  • Тридцать строк на сентябрь, независимо от данных
  • В днях без продаж — 0, а не NULL
  • Одним запросом

Пример

day         revenue
2026-09-01     1000
2026-09-02        0   <- продаж не было
2026-09-03      700

Сначала уточните

Вопросы до кода — половина оценки. Молча начать печатать хуже, чем задать два вопроса.

  • Границы периода фиксированные или «последние 30 дней»?
  • Нужны ли дни в будущем, если отчёт за текущий месяц?
  • Календарная таблица в базе есть или генерировать на лету?
Показать решение Скрыть решение

Решение

SELECT
    days.day::date AS day,
    COALESCE(SUM(p.amount), 0) AS revenue
FROM generate_series(
         DATE '2026-09-01',
         DATE '2026-09-30',
         INTERVAL '1 day'
     ) AS days(day)
LEFT JOIN payments p ON p.paid_at >= days.day
                    AND p.paid_at <  days.day + INTERVAL '1 day'
GROUP BY days.day
ORDER BY days.day;

Почему так

Почему generate_series, а не данные из таблицы

  • В таблице продаж нет строк для дней без продаж — взять их оттуда невозможно в принципе
  • Ряд дат нужно породить: generate_series в Postgres или календарная таблица в других СУБД
  • Понимание «нельзя отфильтровать то, чего нет» — то, что проверяет задача

Почему условие по диапазону, а не date_trunc

  • date_trunc(paid_at) = day — это функция над колонкой, и индекс по paid_at работать не будет
  • Полуинтервал [день, день + 1) оставляет колонку «голой», и планировщик берёт индексный диапазон
  • Этот приём — sargable-условие — регулярно всплывает в вопросах про медленные запросы

Зачем COALESCE

  • SUM по пустой группе даёт NULL, а не 0 — в отчёте появится дыра вместо нуля
  • COALESCE(..., 0) превращает «данных нет» в честный ноль
  • Разница между NULL и 0 в отчётности заметна сразу: графики рвутся, среднее считается неверно

Что спросят дальше

  • Спросят про часовые пояса: границы суток должны считаться в том же поясе, что и данные
  • Спросят про нарастающий итог поверх этого — окно накладывается уже на готовый ряд дней
  • Спросят про другие СУБД: в MySQL generate_series нет, нужна рекурсивная CTE или календарная таблица

Следующая задача

Вернувшиеся пользователи — Простая продуктовая метрика, на которой проверяют самоджойн и аккуратность с датами.