Правилно решение
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