2012-03-13 14 views
8

Data:SQL per contare gli intervalli con il gruppo-by e comprendono 0 conta

table 'thing': 

age 
--- 
3.4 
3.4 
10.1 
40 
45 
49 

voglio contare il numero di cose che per ogni intervallo di 10 anni, ad esempio,

age_range | count 
----------+------- 
     0 |  2 
     10|  1 
     20|  0 
     30|  0 
     40|  3 

Questa interrogazione si avvicina:

SELECT FLOOR(age/10) as age_range, COUNT(*) 
FROM thing 
GROUP BY FLOOR(age/10) ORDER BY FLOOR(age/10); 

uscita:

age_range | count 
-----------+------- 
     0 |  1 
     1 |  2 
     4 |  3 

Tuttavia, non mi mostra gli intervalli che hanno 0 conteggi. Come posso modificare la query in modo che mostri anche gli intervalli tra 0 conteggi?

Ho trovato domande di stackoverflow simili per il conteggio degli intervalli, alcuni per i conteggi 0, ma comportano la necessità di specificare ciascun intervallo (o hard-coding degli intervalli nella query o inserimento degli intervalli in una tabella). Preferirei utilizzare una query generica come quella precedente, in cui non è necessario specificare esplicitamente ciascun intervallo (ad esempio, 0-10, 10-20, 20-30, ...). Sto usando PostgreSQL 9.1.3.

C'è un modo per modificare la query semplice sopra per includere 0 conteggi?

analogo:
Oracle: how to "group by" over a range?
Get frequency distribution of a decimal range in MySQL

risposta

10

generate_series in soccorso:

select 10 * s.d, count(t.age) 
from generate_series(0, 10) s(d) 
left outer join thing t on s.d = floor(t.age/10) 
group by s.d 
order by s.d 

capire il limite superiore per generate_series dovrebbe essere banale con una query separata, ho solo usato 10 come segnaposto .

Questo:

generate_series(0, 10) s(d) 

genera essenzialmente una tabella integrata denominata s con una sola colonna d che contiene i valori da 0 a 10 (compreso).

È possibile racchiudere le due query (una per calcolare l'intervallo, una per calcolare i conteggi) in una funzione, se necessario.

+0

Che bello. Buona funzione da sapere. – Glenn

+0

Risposta elegante, @mu_is_too_short! L'ho provato e ha funzionato. Proprio quello che stavo cercando. Grazie! –

+0

@Glenn: Sì, 'generate_series' è pazzesco-utile, può anche funzionare con timestamp quindi addio tabelle di calendario. –

1

Hai bisogno di un modo per inventare la tabella delle fasce d'età. Il numero di riga di solito funziona bene. Fai un prodotto cartesiano contro un grande tavolo per ottenere un sacco di numeri.

WITH RANGES AS (
SELECT (rownum - 1) * 10 AS age_range 
    FROM (SELECT row_number() OVER() as rownum 
      FROM pg_tables 
     ) n 
     ,(SELECT ceil(max(age)/10) range_end 
      FROM thing 
     ) m 
    WHERE n. rownum <= range_end 
) 
SELECT r.age_range, COUNT(t.age) AS count 
    FROM ranges r 
    LEFT JOIN thing t ON r.age_range = FLOOR(t.age/10) * 10 
    GROUP BY r.age_range 
    ORDER BY r.age_range; 

EDIT: mu è troppo corto ha una risposta molto più elegante, ma se non si dispone di una funzione di generate_series sul db, ... :)

Problemi correlati