Soluzione adeguata
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;
-
Usa
LEFT JOIN
, ovviamente. -
generate_series()
può produrre una tabella di timestamp al volo e molto velocemente. -
In genere è più veloce aggregare prima tu ti unisci. Di recente ho fornito un test case su sqlfiddle.com in questa risposta correlata:
- PostgreSQL:ordine per array
-
Trasmetti il
timestamp
adate
(::date
) per un formato di base. Per ulteriori informazioni usato_char()
. -
GROUP BY 1
è un'abbreviazione di sintassi per fare riferimento alla prima colonna di output. Potrebbe essereGROUP BY day
anche, ma ciò potrebbe entrare in conflitto con una colonna esistente con lo stesso nome. OppureGROUP BY date_trunc('month', date_col)::date
ma è troppo lungo per i miei gusti. -
Funziona con gli argomenti di intervallo disponibili per
date_trunc()
. -
count()
non produce maiNULL
(0
per nessuna riga), ma ilLEFT JOIN
fa.
Per restituire0
invece diNULL
nelSELECT
esterno , usaCOALESCE(some_count, 0) AS some_count
. Il manuale. -
Per una soluzione più generica o intervalli di tempo arbitrari considera questa risposta strettamente correlata:
- Il modo migliore per contare i record in base a intervalli di tempo arbitrari in Rails+Postgres