Правилно решение
SELECT *
FROM (
SELECT day::date
FROM generate_series(timestamp '2007-12-01'
, timestamp '2008-12-01'
, interval '1 month') day
) d
LEFT JOIN (
SELECT date_trunc('month', date_col)::date AS day
, count(*) AS some_count
FROM tbl
WHERE date_col >= date '2007-12-01'
AND date_col <= date '2008-12-06'
-- AND ... more conditions
GROUP BY 1
) t USING (day)
ORDER BY day;
-
Използвайте
LEFT JOIN, разбира се. -
generate_series()може да създаде таблица с времеви марки в движение и много бързо. -
Като цяло е по-бързо да се обобщава преди присъединяваш се. Наскоро предоставих тестов случай на sqlfiddle.com в този свързан отговор:
- PostgreSQL – подреждане по масив
-
Прехвърляне на
timestampдоdate(::date) за основен формат. За повече използвайтеto_char(). -
GROUP BY 1е синтаксис стенография за препратка към първата изходна колона. Може да еGROUP BY dayсъщо, но това може да е в конфликт със съществуваща колона със същото име. ИлиGROUP BY date_trunc('month', date_col)::dateно това е твърде дълго за моя вкус. -
Работи с наличните интервални аргументи за
date_trunc(). -
count()никога не произвеждаNULL(0без редове), ноLEFT JOINправи.
За връщане на0вместоNULLвъв външнияSELECT, използвайтеCOALESCE(some_count, 0) AS some_count. Ръководството. -
За по-общо решение или произволни интервали от време помислете за този тясно свързан отговор:
- Най-добрият начин за преброяване на записи чрез произволни интервали от време в Rails+Postgres