2012-11-16 4 views
7

Quello che voglio ottenere è una statistica con ogni mese da un generate_series e la somma degli ID conteggiati in ogni mese. Questo SQL funziona in PostgreSQL 9.1:Unire una query di conteggio su un generate_series in postgres e anche recuperare valori null come "0"

SELECT (to_char(serie,'yyyy-mm')) AS year, sum(amount)::int AS eintraege FROM (
    SELECT 
     COUNT(mytable.id) as amount, 
     generate_series::date as serie 
     FROM mytable 

    RIGHT JOIN generate_series( 

     (SELECT min(date_from) FROM mytable)::date, 
     (SELECT max(date_from) FROM mytable)::date, 
     interval '1 day') ON generate_series = date(date_from) 
     WHERE version = 1 
     GROUP BY generate_series  
     ) AS foo 
    GROUP BY Year 
    ORDER BY Year ASC; 

E questa è la mia uscita

"2006-12" | 4 
"2007-02" | 1 
"2007-03" | 1 

Ma quello che voglio ottenere è questa uscita (valore "0" nel mese di gennaio):

"2006-12" | 4 
"2007-01" | 0 
"2007-02" | 1 
"2007-03" | 1 

Quindi, se c'è un mese senza id, dovrebbe essere comunque elencato. Qualche idea su come risolvere questo?

Ecco alcuni dati di esempio:

drop table if exists mytable; 
create table mytable(id bigint, version smallint, date_from timestamp without time zone); 
insert into mytable(id, version, date_from) values 

('4084036', '1', '2006-12-22 22:46:35'), 
('4084938', '1', '2006-12-23 16:19:13'), 
('4084938', '2', '2006-12-23 16:20:23'), 
('4084939', '1', '2006-12-23 16:29:14'), 
('4084954', '1', '2006-12-23 16:28:28'), 
('4250653', '1', '2007-02-12 21:58:53'), 
('4250657', '1', '2007-03-12 21:58:53') 
; 
+1

Come sempre, la definizione della tabella di 'mytable' dovrebbe essere nella domanda. E alcuni valori di esempio per andare con esso sarebbero gonfiati. –

risposta

16

Untangled, semplificato e fisso, potrebbe assomigliare a questo:

SELECT to_char(s.tag,'yyyy-mm') AS monat 
     ,count(t.id) AS eintraege 
FROM (
    SELECT generate_series(min(date_from)::date 
         ,max(date_from)::date 
         ,interval '1 day' 
     )::date AS tag 
    FROM mytable t 
    ) s 
LEFT JOIN mytable t ON t.date_from::date = s.tag AND t.version = 1 
GROUP BY 1 
ORDER BY 1; 

Tra tutti i rumori, gli identificatori ingannevoli e il formato non convenzionale il problema reale era nascosto qui:

WHERE version = 1 

Durante l'utilizzo corretto di RIGHT JOIN, avete annullato l'operazione aggiungendo una clausola WHERE che richiedeva un valore distinto da mytable - convertendo lo RIGHT JOIN in uno JOIN in modo efficace.

Tirare la clausola in basso nella condizione JOIN per farlo funzionare.

Ho semplificato un paio di altre cose.

+0

Grazie mille per la risposta e soprattutto per la spiegazione! La tua risposta risolve il problema. – zehpunktbarron