postgresql - sql - jumlah nilai `true`

97
myCol
------
 true
 true
 true
 false
 false
 null

Pada tabel di atas, jika saya melakukan:

select count(*), count(myCol);

saya mendapat 6, 5

Saya mendapatkan 5karena tidak menghitung entri nol.

Bagaimana cara menghitung jumlah nilai sebenarnya (3 dalam contoh)?

(Ini adalah penyederhanaan dan saya sebenarnya menggunakan ekspresi yang jauh lebih rumit dalam fungsi hitungan)

Edit ringkasan: Saya juga ingin menyertakan jumlah biasa (*) dalam kueri, jadi tidak bisa menggunakan klausa where

EoghanM
sumber
Apakah 't' adalah singkatan dari True anf 'f' for False? Atau apakah Anda mencari sesuatu seperti SELECT COUNT (DISTINCT myCol).
Shamit Verma
lihat contoh kedua saya, Anda dapat menambahkan a WHERE myCol = truedi sana jika Anda mau dan jika Anda menghapus yang pertama, *,itu hanya akan mengembalikan nomornya.
vol7ron
@Shamit ya t berarti benar, dan f berarti salah, saya telah memperbarui pertanyaannya
EoghanM
Anda mungkin juga tidak menyederhanakan pertanyaan / kueri Anda ... persyaratan Anda membatasi kemungkinan kinerja yang lebih baik dan orang-orang merespons dengan jawaban yang tidak efisien, yang muncul tanpa alasan yang jelas.
vol7ron
1
@ vol7ron dalam pembelaan saya harus ada beberapa penyederhanaan untuk mengajukan pertanyaan yang dapat dipahami, tetapi ya, saya terlalu menyederhanakan ketika saya awalnya memposting.
EoghanM

Jawaban:

133
SELECT COALESCE(sum(CASE WHEN myCol THEN 1 ELSE 0 END),0) FROM <table name>

atau, seperti yang Anda temukan sendiri:

SELECT count(CASE WHEN myCol THEN 1 END) FROM <table name>
Daniel
sumber
Ini adalah retasan yang bagus dan mendapat jawaban yang benar dari saya. Saya akan menerimanya kecuali seseorang memberikan solusi yang lebih singkat?
EoghanM
2
juga, ada alasan mengapa Anda melakukan penjumlahan (.. THEN 1 ELSE 0) daripada menghitung (.. THEN true else null)?
EoghanM
5
Tidak ... hanya saja saya tidak yakin nilai mana yang akan dihitung () dihitung ... dan saya tahu jumlah itu berhasil. Namun berhati-hatilah: Setelah dipikir-pikir, saya percaya bahwa sum () di atas hanya nilai null akan mengembalikan null, jadi itu harus COALESCE (sum (...), 0) untuk Anda, atau, dengan kata lain, count () lebih baik,
Daniel
1
@EoghanM, lihat jawaban singkat yang melibatkan pemeran.
Dwayne Towell
1
Anda sebenarnya bisa menghilangkan ELSE nulluntuk mendapatkan hasil yang sama.
200_sukses
91

Transmisikan Boolean menjadi integer dan jumlah.

SELECT count(*),sum(myCol::int);

Anda mendapatkan 6,3.

Dwayne Towell
sumber
3
Plus1: Retasan yang bagus! Ini mungkin lebih cepat daripada solusi saya.
Daniel
1
Ini adalah solusi terbaik dan terpendek (dan memiliki kesetaraan di banyak lingkungan pemrograman dan perangkat lunak lainnya). Harus dipilih lebih banyak
3
'Cast to int and count' jelas yang paling ringkas, tapi itu bukan yang terbaik. Saya tidak akan mendukung ini, karena sementara banyak lingkungan menggunakan representasi 0/1 untuk false / true, banyak yang menggunakan 0 / bukan nol, termasuk -1. Saya setuju ini adalah "retasan", dan gips cukup tidak pasti jika bukan "retasan". Tidak akan memberi suara negatif tetapi sekali lagi, tidak akan mendukung.
Andrew Wolfe
82

Sejak PostgreSQL 9.4 ada FILTERklausul , yang memungkinkan kueri yang sangat ringkas untuk menghitung nilai sebenarnya:

select count(*) filter (where myCol)
from tbl;

Kueri di atas adalah contoh yang buruk karena klausa WHERE yang sederhana sudah cukup, dan hanya untuk mendemonstrasikan sintaks. Di mana klausa FILTER menonjol adalah mudah untuk menggabungkan dengan agregat lain:

select count(*), -- all
       count(myCol), -- non null
       count(*) filter (where myCol) -- true
from tbl;

Klausa ini sangat berguna untuk agregat di kolom yang menggunakan kolom lain sebagai predikat, sekaligus memungkinkan untuk mengambil agregat yang difilter secara berbeda dalam satu kueri:

select count(*),
       sum(otherCol) filter (where myCol)
from tbl;
Ilja Everilä
sumber
2
Ini adalah jawaban terbaik untuk PG> 9,4 dan sangat cepat
Juan Ricardo
47

mungkin, pendekatan terbaik adalah dengan menggunakan fungsi nullif.

secara umum

select
    count(nullif(myCol = false, true)),  -- count true values
    count(nullif(myCol = true, true)),   -- count false values
    count(myCol);

atau singkatnya

select
    count(nullif(myCol, true)),  -- count false values
    count(nullif(myCol, false)), -- count true values
    count(myCol);

http://www.postgresql.org/docs/9.0/static/functions-conditional.html

wrobell
sumber
2
"Secara umum" Anda terlihat salah: AFAICS, nullif([boolean expression], true)akan ditampilkan falsejika [ekspresi boolean] salah, dan nulljika benar, maka Anda akan menghitung nilai yang salah. Saya pikir Anda mau nullif([boolean expression], false).
rjmunro
ya, kasus "umum" seharusnya sebaliknya. tetap. Terima kasih.
wrobell
1
Yuk. Perbaikan itu sangat membingungkan. AFAICS, sekarang akan menghitung nilai benar atau nol. Menurut saya, mengulanginya sehingga Anda selalu nullif([boolean expression], false)membuatnya lebih mudah dibaca. Anda kemudian dapat memvariasikan bagian ekspresi boolean menjadi apa pun yang Anda suka, dalam hal ini myCol = trueuntuk menghitung nilai yang benar, atau myCol = falseuntuk menghitung nilai yang salah, atau name='john'untuk menghitung orang yang disebut john dll.
rjmunro
19

Solusi terpendek dan paling malas (tanpa casting) adalah dengan menggunakan rumus:

SELECT COUNT(myCol OR NULL) FROM myTable;

Cobalah sendiri:

SELECT COUNT(x < 7 OR NULL)
   FROM GENERATE_SERIES(0,10) t(x);

memberikan hasil yang sama dengan

SELECT SUM(CASE WHEN x < 7 THEN 1 ELSE 0 END)
   FROM GENERATE_SERIES(0,10) t(x);
Le Droid
sumber
Ini jelas merupakan solusi yang lebih baik daripada saya :)
Daniel
Jawaban yang sangat berwawasan.
lucasarruda
7

Di MySQL, Anda juga dapat melakukan ini:

SELECT count(*) AS total
     , sum(myCol) AS countTrue --yes, you can add TRUEs as TRUE=1 and FALSE=0 !!
FROM yourTable
;

Saya pikir di Postgres, ini berfungsi:

SELECT count(*) AS total
     , sum(myCol::int) AS countTrue --convert Boolean to Integer
FROM yourTable
;

atau lebih baik (untuk menghindari :: dan menggunakan sintaks SQL standar):

SELECT count(*) AS total
     , sum(CAST(myCol AS int)) AS countTrue --convert Boolean to Integer
FROM yourTable
;
ypercubeᵀᴹ
sumber
Ini adalah solusi paling sederhana yang pernah saya lihat ^ _ ^
JiaHao Xu
7
select f1,
       CASE WHEN f1 = 't' THEN COUNT(*) 
            WHEN f1 = 'f' THEN COUNT(*) 
            END AS counts,
       (SELECT COUNT(*) FROM mytable) AS total_counts
from mytable
group by f1

Atau Mungkin ini

SELECT SUM(CASE WHEN f1 = 't' THEN 1 END) AS t,
       SUM(CASE WHEN f1 = 'f' THEN 1 END) AS f,
       SUM(CASE WHEN f1 NOT IN ('t','f') OR f1 IS NULL THEN 1 END) AS others,
       SUM(CASE WHEN f1 IS NOT NULL OR f1 IS NULL THEN 1 ELSE 0 END) AS total_count
FROM mytable;
Kuberchaun
sumber
+1 Jika myColekspresi adalah boolean, Anda dapat mengganti cek denganwhere (myCol)
ypercubeᵀᴹ
maaf saya terlalu menyederhanakan contoh saya: Saya tidak dapat menggunakan klausa where karena saya juga ingin mengembalikan jumlah total yang mewakili jumlah baris, serta hitungan nilai sebenarnya.
EoghanM
7

Cukup ubah bidang boolean menjadi bilangan bulat dan lakukan penjumlahan. Ini akan bekerja pada postgresql:

select sum(myCol::int) from <table name>

Semoga membantu!

Jaspreet Singh
sumber
Ini tidak lebih cepat atau lebih tepat daripada solusi lainnya. Saya yakin Anda berasal dari Oracle saat menggunakan int karena boolean lebih intuitif untuk Anda.
Daniel
4
SELECT count(*)         -- or count(myCol)
FROM   <table name>     -- replace <table name> with your table
WHERE  myCol = true;

Berikut cara dengan Fungsi Windowing:

SELECT DISTINCT *, count(*) over(partition by myCol)
FROM   <table name>;

-- Outputs:
-- --------------
-- myCol | count
-- ------+-------
--  f    |  2
--  t    |  3
--       |  1
vol7ron
sumber
maaf saya tidak dapat mengembalikan beberapa baris untuk contoh yang lebih rumit yang saya terapkan solusi ini.
EoghanM
Ya, tetapi Anda dapat membatasinya lebih lanjut dengan hanya menambahkan WHERE myCol = true. Saya memberikan contoh kedua bukan karena ini lebih cepat, tetapi lebih sebagai bagian pendidikan untuk fungsi windowing Postgres, yang banyak pengguna tidak nyaman, atau tidak tahu.
vol7ron
0
select count(myCol)
from mytable
group by myCol
;

akan mengelompokkan 3 kemungkinan status bool (false, true, 0) dalam tiga baris terutama berguna saat mengelompokkan bersama dengan kolom lain seperti hari

hazard5000
sumber