Solución adecuada
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
, por supuesto. -
generate_series()
puede producir una tabla de marcas de tiempo sobre la marcha, y muy rápido. -
Por lo general, es más rápido agregar antes Tú te unes. Recientemente proporcioné un caso de prueba en sqlfiddle.com en esta respuesta relacionada:
- PostgreSQL:ordenar por matriz
-
Enviar la
timestamp
adate
(::date
) para un formato básico. Para más usoto_char()
. -
GROUP BY 1
es una forma abreviada de sintaxis para hacer referencia a la primera columna de salida. Podría serGROUP BY day
también, pero eso podría entrar en conflicto con una columna existente del mismo nombre. OGROUP BY date_trunc('month', date_col)::date
pero eso es demasiado largo para mi gusto. -
Funciona con los argumentos de intervalo disponibles para
date_trunc()
. -
count()
nunca produceNULL
(0
sin filas), pero elLEFT JOIN
lo hace.
Para devolver0
en lugar deNULL
en el exteriorSELECT
, usaCOALESCE(some_count, 0) AS some_count
. El manual. -
Para una solución más genérica o intervalos de tiempo arbitrarios considere esta respuesta estrechamente relacionada:
- La mejor manera de contar registros por intervalos de tiempo arbitrarios en Rails+Postgres