Zwraca liczniki dla wielu zakresów w pojedynczej instrukcji SELECT

9

Mam tabelę bazy danych Postgres, fooktóra między innymi zawiera kolumnę z scorezakresu od 0 do 10. Chcę, aby zapytanie zwróciło całkowitą liczbę wyników, liczbę wyników od 0 do 3, liczbę wyników między 4 i 6, a liczba wyników między 7 a 10. Coś w stylu:

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;

Próbowałem tego, ale wystąpił błąd SELECTw COUNTinstrukcjach. Jakieś pomysły, jak to zrobić? Jestem pewien, że w Postgres jest bardzo prosty sposób. Po prostu nie mogę znaleźć odpowiednich warunków dla Google.

Bryan
źródło

Odpowiedzi:

7

Wystarczy użyć SUM()instrukcji warunkowych w kolumnie dla każdego zakresu liczb. Suma może zostać zsumowana po prostu przy użyciu SUM(1), zakładając, że wszystkie dane w tabeli mieszczą się w jednym z zakresów - jeśli nie, po prostu ogranicz je, jak w przypadku innych.

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;

Łącze Fiddle SQL .

Philᵀᴹ
źródło
8

FILTERKlauzula zagregowana w Postgres 9.4+

Od wersji Postgres 9.4 istnieje czysty i szybki (standardowy SQL) sposób:

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;

totaldodaje się low, midi high, o ile nie są zaangażowane NULL lub inne wartości.

Spinki do mankietów:

Przeczytaj także poniżej.

Postgres 9.3-

Istnieje kilka technik:

@Phil podał standardowy sposób z CASEinstrukcją (z wyjątkiem sum(1), który nie jest standardowym sposobem). Lubię używać krótszej formy:

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;

Jeśli twoje wartości są zdefiniowane w pytaniu (tylko 0- 10możliwe), uprość dalej:

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;

Trochę krótszy, niewiele szybszy.

Subtelne różnice

subtelne różnice w porównaniu do sum()w odpowiedzi Phila :

  • Co najważniejsze, według dokumentacji :

    Należy zauważyć, że oprócz counttych funkcji zwracają wartość zerową, gdy nie są zaznaczone żadne wiersze. W szczególności sumbrak wierszy zwraca zero, a nie zero, jak można się spodziewać ...

  • count(*) to standardowy sposób i nieco szybszy niż sum(1). Ponownie obowiązuje wartość null vs. 0.

Każde z tych zapytań (w tym Phila) zlicza wartości null total. Jeśli nie jest to pożądane, użyj zamiast tego:

count(score) AS total_not_null

Fiddle SQL w str. 9.3.
db <> skrzypce tutaj na stronie 10.

Erwin Brandstetter
źródło