Správné řešení
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;
-
Použijte
LEFT JOIN
, samozřejmě. -
generate_series()
dokáže vytvořit tabulku časových razítek za běhu a velmi rychle. -
Obecně je rychlejší agregovat před přidáš se. Nedávno jsem poskytl testovací případ na sqlfiddle.com v této související odpovědi:
- PostgreSQL – řazení podle pole
-
Odešlete
timestamp
dodate
(::date
) pro základní formát. Pro více použijteto_char()
. -
GROUP BY 1
je zkratka syntaxe odkazující na první výstupní sloupec. Může to býtGROUP BY day
také, ale to může být v konfliktu s existujícím sloupcem se stejným názvem. NeboGROUP BY date_trunc('month', date_col)::date
ale to je na můj vkus příliš dlouhé. -
Pracuje s dostupnými argumenty intervalu pro
date_trunc()
. -
count()
nikdy nevytváříNULL
(0
pro žádné řádky), aleLEFT JOIN
ano.
Vrátí0
místoNULL
ve vnějšímSELECT
, použijteCOALESCE(some_count, 0) AS some_count
. Manuál. -
Pro obecnější řešení nebo libovolné časové intervaly zvažte tuto úzce související odpověď:
- Nejlepší způsob, jak počítat záznamy podle libovolných časových intervalů v Rails+Postgres