Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як побудувати звіт по днях без пропусків для днів без даних?

Проблема: групування за датою повертає лише дні, у які були дані. Для графіка «замовлень по днях» дні без замовлень просто зникають, і лінія графіка бреше.

SELECT DATE(created_at) AS day, COUNT(*) FROM orders GROUP BY day;
-- 2026-10-01: 15, 2026-10-03: 9   (2 жовтня пропущено, хоча там 0)

Рішення - згенерувати повний календар і приєднати до нього дані:

WITH RECURSIVE calendar AS (
    SELECT DATE('2026-10-01') AS day
    UNION ALL
    SELECT day + INTERVAL 1 DAY
    FROM calendar
    WHERE day < '2026-10-31'
)
SELECT c.day, COUNT(o.id) AS orders
FROM calendar c
LEFT JOIN orders o
    ON o.created_at >= c.day
   AND o.created_at < c.day + INTERVAL 1 DAY
GROUP BY c.day
ORDER BY c.day;

Ключові деталі:

  • LEFT JOIN від календаря, а не від даних - щоб дні без замовлень лишилися.
  • COUNT(o.id), а не COUNT(*) - COUNT(*) порахує рядок календаря й дасть 1 замість 0.
  • Умова з'єднання діапазоном, а не DATE(o.created_at) = c.day - так працює індекс на created_at.
  • Ліміт рекурсії: cte_max_recursion_depth за замовчуванням 1000. Для календаря на кілька років його збільшують для сесії.

Часові пояси: «день» залежить від поясу. Якщо created_at зберігається в UTC, а звіт - за київським часом, межі днів треба зсунути (CONVERT_TZ або обчислені межі), інакше замовлення о 01:00 за Києвом потраплять у попередній день.

Альтернативи:

  • Постійна таблиця-календар з датами на роки вперед - корисна, якщо звітів багато, і в неї можна додати атрибути (вихідні, свята, номер тижня).
  • Заповнення пропусків у застосунку - згенерувати діапазон дат у PHP (CarbonPeriod) і злити з результатом запиту.

У PostgreSQL для цього є generate_series().

Докладніше в документації: WITH (CTE)

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання