Restituisce i conteggi per più intervalli in una singola istruzione SELECT


9

Ho una tabella di database Postgres fooche, tra le altre cose, ha una colonna scoreche varia da 0 a 10. Voglio una query per restituire il numero totale di punteggi, il numero di punteggi tra 0 e 3, il numero di punteggi tra 4 e 6 e il numero di punteggi tra 7 e 10. Qualcosa di simile al seguente:

SELECT
  COUNT(*) as total,
  COUNT(
    SELECT * from foo where score between 0 and 3;
  ) as low,
  COUNT(
    SELECT * from foo where score between 4 and 6;
  ) as mid,
  COUNT(
    SELECT * from foo where score between 7 and 10;
  ) as high
FROM foo;

Ho provato questo, ma ho riscontrato un errore con SELECTle COUNTdichiarazioni. Qualche idea su come posso farlo? Sono sicuro che ci sia un modo super semplice in Postgres. Non riesco proprio a capire i termini corretti per Google.

Risposte:


7

Usa solo le SUM()istruzioni condizionali per colonna per ogni intervallo di numeri. Il totale può essere sommato semplicemente usando SUM(1), supponendo che tutti i dati nella tabella siano all'interno di uno degli intervalli - in caso contrario, limitalo come con gli altri.

select sum(case when score between 0 and 3 then 1 else 0 end) as minrange,
       sum(case when score between 4 and 6 then 1 else 0 end) as midrange,
       sum(case when score between 7 and 10 then 1 else 0 end) as maxrange,
       sum(1) as total
from foo;

Collegamento SQL Fiddle .


8

FILTERClausola aggregata in Postgres 9.4+

Da Postgres 9.4 esiste un modo pulito e veloce (standard SQL):

SELECT count(*) FILTER (WHERE score BETWEEN 0 AND 3)  AS low
     , count(*) FILTER (WHERE score BETWEEN 4 AND 7)  AS mid
     , count(*) FILTER (WHERE score BETWEEN 8 AND 10) AS high
     , count(*)                                       AS total
FROM   foo;

totalaggiunge up low, mide high, a meno che non siano coinvolti NULL o di altri valori.

link:

Leggi anche sotto.

Postgres 9.3-

Esistono un paio di tecniche:

@Phil ha fornito una CASEdichiarazione standard (ad eccezione di sum(1), che non è la modalità standard). Mi piace usare una forma più breve:

SELECT count(score BETWEEN 0 AND 3  OR NULL) AS low
     , count(score BETWEEN 4 AND 6  OR NULL) AS mid
     , count(score BETWEEN 7 AND 10 OR NULL) AS high
     , count(*)                              AS total
FROM   foo;

Se i tuoi valori sono quelli definiti nella tua domanda (solo 0- 10possibile), semplifica ulteriormente:

SELECT count(score < 4 OR NULL)             AS low
     , count(score BETWEEN 4 AND 6 OR NULL) AS mid
     , count(score > 6 OR NULL)             AS high
     , count(*)                             AS total
FROM   foo;

Un po 'più corto, a malapena più veloce.

Differenze sottili

Ci sono sottili differenze quando rispetto a sum()in risposta di Phil :

  • Ancora più importante, per documentazione :

    Va notato che, ad eccezione di count, queste funzioni restituiscono un valore null quando non è selezionata alcuna riga. In particolare, sumdi nessuna riga restituisce null, non zero come ci si potrebbe aspettare, ...

  • count(*) è il modo standard e un po 'più veloce di sum(1). Ancora una volta, si applica null vs. 0.

Ognuna di queste query (inclusa quella di Phil) conta valori nulli per total. Se ciò non è desiderabile, utilizzare invece:

count(score) AS total_not_null

SQL Fiddle in pag. 9.3.
db <> violino qui a pag.10.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.