Kembali menghitung untuk beberapa rentang dalam satu pernyataan SELECT

9

Saya memiliki tabel database Postgres fooyang, antara lain, memiliki kolom untuk scorerentang 0 - 10. Saya ingin kueri mengembalikan jumlah total skor, jumlah skor antara 0 dan 3, jumlah skor antara 4 dan 6, dan jumlah skor antara 7 dan 10. Sesuatu seperti yang berikut:

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;

Saya mencoba ini, tetapi mendapat kesalahan dengan SELECTdalam COUNTpernyataan. Ada ide bagaimana saya bisa melakukan ini? Saya yakin ada cara super sederhana di Postgres. Saya hanya tidak bisa mengetahui istilah yang tepat untuk Google untuk.

Bryan
sumber

Jawaban:

7

Cukup gunakan SUM()pernyataan kondisional per kolom untuk setiap rentang angka. Total dapat diringkas hanya dengan menggunakan SUM(1), dengan asumsi semua data dalam tabel berada dalam salah satu rentang - jika tidak, batasi saja seperti yang lainnya.

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;

Tautan SQL Fiddle .

Philᵀᴹ
sumber
8

FILTERKlausa agregat di Postgres 9.4+

Karena Postgres 9.4 ada cara yang bersih dan cepat (standar 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;

totaldijumlahkan low, middan high, kecuali NULL atau nilai lain yang terlibat.

Tautan:

Baca juga di bawah ini.

Postgres 9.3-

Ada beberapa teknik:

@Phil memberikan cara standar dengan CASEpernyataan (kecuali untuk sum(1), yang bukan cara standar). Saya suka menggunakan formulir yang lebih pendek:

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;

Jika nilai Anda sebagaimana didefinisikan dalam pertanyaan Anda (hanya 0- 10mungkin), sederhanakan lebih lanjut:

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;

Sedikit lebih pendek, nyaris tidak lebih cepat.

Perbedaan yang halus

Ada perbedaan halus jika dibandingkan dengan sum()dalam jawaban Phil :

  • Yang paling penting, per dokumentasi :

    Perlu dicatat bahwa kecuali untuk count, fungsi-fungsi ini mengembalikan nilai nol ketika tidak ada baris yang dipilih. Secara khusus, sumtanpa baris mengembalikan nol, bukan nol seperti yang mungkin diharapkan, ...

  • count(*) adalah cara standar dan sedikit lebih cepat daripada sum(1). Sekali lagi, nol vs 0 berlaku.

Salah satu dari pertanyaan ini (termasuk Phil) menghitung nilai null untuk total. Jika itu tidak diinginkan, gunakan saja:

count(score) AS total_not_null

SQL Fiddle di halaman 9.3.
db <> biola di sini di halaman 10.

Erwin Brandstetter
sumber