PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Postgres:come restituire le righe con 0 conteggio per i dati mancanti?

Soluzione adeguata

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 , ovviamente.

  • generate_series() può produrre una tabella di timestamp al volo e molto velocemente.

  • In genere è più veloce aggregare prima tu ti unisci. Di recente ho fornito un test case su sqlfiddle.com in questa risposta correlata:

    • PostgreSQL:ordine per array
  • Trasmetti il ​​timestamp a date (::date ) per un formato di base. Per ulteriori informazioni usa to_char() .

  • GROUP BY 1 è un'abbreviazione di sintassi per fare riferimento alla prima colonna di output. Potrebbe essere GROUP BY day anche, ma ciò potrebbe entrare in conflitto con una colonna esistente con lo stesso nome. Oppure GROUP BY date_trunc('month', date_col)::date ma è troppo lungo per i miei gusti.

  • Funziona con gli argomenti di intervallo disponibili per date_trunc() .

  • count() non produce mai NULL (0 per nessuna riga), ma il LEFT JOIN fa.
    Per restituire 0 invece di NULL nel SELECT esterno , usa COALESCE(some_count, 0) AS some_count . Il manuale.

  • Per una soluzione più generica o intervalli di tempo arbitrari considera questa risposta strettamente correlata:

    • Il modo migliore per contare i record in base a intervalli di tempo arbitrari in Rails+Postgres