PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Postgres - como retornar linhas com contagem 0 para dados ausentes?



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