Korrekt 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;
-
Brug
LEFT JOIN
selvfølgelig. -
generate_series()
kan producere en tabel med tidsstempler i farten, og meget hurtigt. -
Det er generelt hurtigere at samle før du tilslutter dig. Jeg har for nylig leveret en testcase på sqlfiddle.com i dette relaterede svar:
- PostgreSQL - bestil efter en matrix
-
Cast
timestamp
tildate
(::date
) for et grundlæggende format. For mere brugto_char()
. -
GROUP BY 1
er syntaksstenografi for at referere til den første outputkolonne. Kunne væreGROUP BY day
også, men det kan være i konflikt med en eksisterende kolonne af samme navn. EllerGROUP BY date_trunc('month', date_col)::date
men det er for langt efter min smag. -
Fungerer med de tilgængelige intervalargumenter for
date_trunc()
. -
count()
producerer aldrigNULL
(0
for ingen rækker), menLEFT JOIN
gør.
For at returnere0
i stedet forNULL
i den ydreSELECT
, brugCOALESCE(some_count, 0) AS some_count
. Manualen. -
For en mere generisk løsning eller vilkårlige tidsintervaller overvej dette nært beslægtede svar:
- Bedste måde at tælle poster efter vilkårlige tidsintervaller i Rails+Postgres