Solução adequada
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;
-
Use LEFT JOIN
, é claro.
-
generate_series()
pode produzir uma tabela de timestamps em tempo real, e muito rápido.
-
Geralmente é mais rápido agregar antes você se junta. Recentemente, forneci um caso de teste no sqlfiddle.com nesta resposta relacionada:
- PostgreSQL - ordena por uma matriz
-
Transmitir o timestamp
para date
(::date
) para um formato básico. Para mais, use to_char()
.
-
GROUP BY 1
é um atalho de sintaxe para fazer referência à primeira coluna de saída. Pode ser GROUP BY day
também, mas isso pode entrar em conflito com uma coluna existente com o mesmo nome. Ou GROUP BY date_trunc('month', date_col)::date
mas isso é muito longo para o meu gosto.
-
Funciona com os argumentos de intervalo disponíveis para date_trunc()
.
-
count()
nunca produz NULL
(0
para nenhuma linha), mas o LEFT JOIN
faz.
Para retornar 0
em vez de NULL
no SELECT
externo , use COALESCE(some_count, 0) AS some_count
. O manual.
-
Para uma solução mais genérica ou intervalos de tempo arbitrários considere esta resposta intimamente relacionada:
- Melhor maneira de contar registros por intervalos de tempo arbitrários em Rails+Postgres