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