Właściwe rozwiązanie
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;
-
Użyj
LEFT JOIN
, oczywiście. -
generate_series()
może tworzyć tabelę znaczników czasu w locie i bardzo szybko. -
Zazwyczaj agregacja jest szybsza przed ty dołącz. Niedawno przedstawiłem przypadek testowy na sqlfiddle.com w tej powiązanej odpowiedzi:
- PostgreSQL — uporządkowanie według tablicy
-
Prześlij
timestamp
dodate
(::date
) dla formatu podstawowego. Aby uzyskać więcej, użyjto_char()
. -
GROUP BY 1
jest skrótem składni odnoszącym się do pierwszej kolumny wyjściowej. Może byćGROUP BY day
ale może to kolidować z istniejącą kolumną o tej samej nazwie. LubGROUP BY date_trunc('month', date_col)::date
ale to za długo jak na mój gust. -
Działa z dostępnymi argumentami interwału dla
date_trunc()
. -
count()
nigdy nie tworzyNULL
(0
bez wierszy), aleLEFT JOIN
robi.
Aby zwrócić0
zamiastNULL
w zewnętrznymSELECT
, użyjCOALESCE(some_count, 0) AS some_count
. Instrukcja. -
Dla bardziej ogólnego rozwiązania lub arbitralnych przedziałów czasowych rozważ tę ściśle powiązaną odpowiedź:
- Najlepszy sposób na liczenie rekordów w dowolnych odstępach czasu w Rails+Postgres