Rätt lösning
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;
-
Använd
LEFT JOIN
, naturligtvis. -
generate_series()
kan producera en tabell med tidsstämplar i farten, och mycket snabbt. -
Det går i allmänhet snabbare att samla före du går med. Jag gav nyligen ett testfall på sqlfiddle.com i detta relaterade svar:
- PostgreSQL - ordna efter en array
-
Kasta
timestamp
tilldate
(::date
) för ett grundläggande format. För mer användto_char()
. -
GROUP BY 1
är syntaxstenografi för att referera till den första utdatakolumnen. Kan varaGROUP BY day
också, men det kan komma i konflikt med en befintlig kolumn med samma namn. EllerGROUP BY date_trunc('month', date_col)::date
men det är för långt för min smak. -
Fungerar med tillgängliga intervallargument för
date_trunc()
. -
count()
producerar aldrigNULL
(0
för inga rader), menLEFT JOIN
gör.
För att returnera0
istället förNULL
i den yttreSELECT
, användCOALESCE(some_count, 0) AS some_count
. Manualen. -
För en mer generisk lösning eller godtyckliga tidsintervall överväg detta närbesläktade svar:
- Bästa sättet att räkna poster efter godtyckliga tidsintervall i Rails+Postgres