it-swarm.com.de

Rückgabewerte für mehrere Bereiche in einer einzelnen SELECT-Anweisung

Ich habe eine Postgres-Datenbanktabelle foo, die unter anderem eine Spalte für score im Bereich von 0 bis 10 enthält. Ich möchte, dass eine Abfrage die Gesamtzahl der Bewertungen und die Anzahl der Punkte zurückgibt Punkte zwischen 0 und 3, die Anzahl der Punkte zwischen 4 und 6 und die Anzahl der Punkte zwischen 7 und 10. So etwas wie das Folgende:

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;

Ich habe dies versucht, aber einen Fehler mit dem SELECT in den COUNT -Anweisungen erhalten. Irgendwelche Ideen, wie ich das machen kann? Ich bin mir sicher, dass es in Postgres einen super einfachen Weg gibt. Ich kann einfach nicht die richtigen Begriffe für Google herausfinden.

9
Bryan

Verwenden Sie einfach bedingte SUM() Anweisungen pro Spalte für jeden Nummernkreis. Die Summe kann einfach mit SUM(1) summiert werden, vorausgesetzt, alle Daten in der Tabelle liegen innerhalb eines der Bereiche - wenn nicht, beschränken Sie sie einfach wie bei den anderen.

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;

SQL Fiddle Link .

7
Philᵀᴹ

Aggregate FILTER -Klausel in Postgres 9.4+

Seit Postgres 9.4 gibt es einen sauberen und schnellen Weg (SQL-Standard):

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;

total addiert low, mid und high, sofern nicht NULL oder andere Werte beteiligt sind.

Links:

Lesen Sie auch unten.

Postgres 9.3-

Es gibt einige Techniken:

@ Phil hat den Standardweg mit einer CASE - Anweisung versehen (mit Ausnahme von sum(1), was nicht der Standardweg ist). Ich benutze gerne eine kürzere Form:

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;

Wenn Ihre Werte der Definition in Ihrer Frage entsprechen (nur 0 - 10 Möglich), vereinfachen Sie dies weiter:

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;

Ein bisschen kürzer, kaum schneller.

Feine Unterschiede

Es gibt subtile Unterschiede im Vergleich zu sum() in Phils Antwort :

  • Am wichtigsten ist, gemäß Dokumentation :

    Es ist zu beachten, dass diese Funktionen mit Ausnahme von count einen Nullwert zurückgeben, wenn keine Zeilen ausgewählt sind. Insbesondere gibt sum ohne Zeilen null zurück, nicht null, wie man erwarten könnte, ...

  • count(*) is der Standardweg und etwas schneller als sum(1). Auch hier gilt null gegen 0.

Jede dieser Abfragen (einschließlich der von Phil) zählt Nullwerte für total. Wenn dies nicht wünschenswert ist, verwenden Sie stattdessen:

count(score) AS total_not_null

SQL Fiddle in S. 9.3.
db <> fiddle hier in S. 10.

8