


Обычная группировка по дате пропускает дни, за которые в таблице нет строк. Постройте календарь через generate_series, затем присоедините счётчики через LEFT JOIN. На учебном примере Mentoring.digital можно проверить, что у каждой даты появилась строка.
В generate_series(0, 6) входят обе границы. Сложение начальной даты с каждым целым смещением даёт семь значений типа date. Отдельно считаем события по дням, чтобы по одной дате в правой части соединения оставалась одна строка.
WITH calendar AS (
SELECT DATE '2026-11-01' + n AS day
FROM generate_series(0, 6) AS offsets(n)
),
events(event_day) AS (
VALUES (DATE '2026-11-02'),
(DATE '2026-11-02'),
(DATE '2026-11-05')
),
daily AS (
SELECT event_day AS day, count(*) AS total
FROM events
GROUP BY event_day
)
SELECT c.day, COALESCE(d.total, 0) AS events
FROM calendar c
LEFT JOIN daily d USING (day)
ORDER BY c.day;
В этом наборе 2 ноября должно получиться два события, 5 ноября одно, в остальных строках ноль. При пустом наборе событий календарь останется, потому что он стоит слева в соединении. COALESCE заменяет отсутствующий счётчик на ноль.
Ограничьте события нужным периодом до группировки. Если время хранится как timestamptz, выберите часовой пояс отчёта перед переводом времени в дату. Фильтр по полю правой таблицы после LEFT JOIN может убрать строки без совпадения, поэтому проверьте хотя бы один пустой день и границы диапазона.
Подобные отчёты удобно отрабатывать на занятиях по SQL с задачами. Расхождения по дням можно разобрать с ментором по SQL на маленьком наборе строк.