postgresql - sql - "gerçek" değerlerin sayısı


98
myCol
------
 true
 true
 true
 false
 false
 null

Yukarıdaki tabloda, yaparsam:

select count(*), count(myCol);

alırım 6, 5

Ben olsun 5o boş giriş sayılmaz olarak.

Gerçek değerlerin sayısını da nasıl sayarım (örnekte 3)?

(Bu bir basitleştirmedir ve aslında sayma işlevi içinde çok daha karmaşık bir ifade kullanıyorum)

Özeti düzenle: Sorguya düz bir sayı (*) da eklemek istiyorum, bu yüzden where cümlesi kullanamıyorum


'T' True ve 'f' False anlamına mı geliyor? Veya SELECT COUNT (DISTINCT myCol) gibi bir şey mi arıyorsunuz?
Shamit Verma

İkinci örneğime bir bakın, isterseniz WHERE myCol = trueoraya bir atabilirsiniz ve ilkini kaldırırsanız, *,sadece numarayı döndürür.
vol7ron

@Shamit yes t doğru anlamına gelir ve f yanlış anlamına gelir, soruyu güncelledim
EoghanM

Sorunuzu / sorgunuzu basitleştirmeyebilirsiniz ... Gereksinimleriniz daha iyi performans olanaklarını kısıtlar ve insanlar, iyi bir neden olmaksızın çarpışan verimsiz yanıtlarla yanıt verir.
vol7ron

1
@ vol7ron benim savunmamda anlaşılır bir soru sormak için bazı basitleştirmeler olmalı, ama evet, ilk gönderdiğimde fazla basitleştirdim.
EoghanM

Yanıtlar:


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

ya da kendiniz için öğrendiğiniz gibi:

SELECT count(CASE WHEN myCol THEN 1 END) FROM <table name>

Bu iyi bir hack ve doğru cevabı benden alıyor. Birisi daha kısa bir çözüm bulmadıkça kabul edeceğim?
EoghanM

2
ayrıca, saymak yerine (.. SONRA 1 BAŞKA 0) toplamanın herhangi bir nedeni var mı?
EoghanM

5
Hayır ... sadece hangi değerlerin sayılacağından () emin değildim ... ve bu toplamın hile yaptığını biliyordum. Ama dikkat: İkinci düşüncede, sum () 'un sadece boş değerler üzerinden null döndüreceğine inanıyorum, bu yüzden sizin için COALESCE (sum (...), 0) olmalı, ya da başka bir deyişle, count () daha iyidir,
Daniel

1
@EoghanM, oyuncularla ilgili daha kısa cevaba bakın.
Dwayne Towell

1
Aslında ELSE nullaynı sonucu almayı ihmal edebilirsiniz .
200_success

92

Boolean'ı bir tamsayı ve toplama çevirin.

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

Sen alırsın 6,3.


3
Artı1: Güzel hack! Bu muhtemelen benim çözümümden daha hızlı.
Daniel

1
Bu en iyi ve en kısa çözümdür (ve diğer birçok programlama ortamında ve yazılımda eşdeğerleri vardır). Daha fazla

3
'İnt and count' açıkça en özlü olanıdır, ancak bu onu en iyi yapmaz. Bunu onaylamayacağım çünkü birçok ortam yanlış / doğru için 0/1 temsilini kullanırken, çoğu -1 dahil 0 / sıfır olmayan kullanır. Bunun bir "hack" olduğuna katılıyorum ve yayınlar "hack" olmadıklarında yeterince riskli. Olumsuz oy vermeyecek ama yine onaylamayacak.
Andrew Wolfe

86

PostgreSQL 9.4'ten beri , çok kısa bir sorgunun gerçek değerleri saymasına izin veren bir FILTERcümle vardır :

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

Yukarıdaki sorgu, basit bir WHERE cümlesinin yeterli olacağı için kötü bir örnektir ve yalnızca sözdizimini göstermek içindir. FILTER cümlesinin parladığı yer, diğer kümelerle birleştirmenin kolay olmasıdır:

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

Bu yan tümce özellikle, tek bir sorguda farklı şekilde filtrelenmiş kümelerin getirilmesine izin verirken, dayanak olarak başka bir sütunu kullanan bir sütundaki kümeler için kullanışlıdır:

select count(*),
       sum(otherCol) filter (where myCol)
from tbl;

2
Bu, PG> 9,4 için en iyi cevap ve inanılmaz derecede hızlı
Juan Ricardo

47

muhtemelen, en iyi yaklaşım nullif işlevini kullanmaktır.

Genel olarak

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

veya kısaca

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


2
Sizin "genel olarak" yanlış görünüyor: AFAICS, eğer [boolean ifadesi] yanlışsa nullif([boolean expression], true)dönecektir falseve nulleğer doğruysa, yanlış değerleri sayacaksınız . Senin istediğini düşünüyorum nullif([boolean expression], false).
rjmunro

evet, "genel" durum tam tersi olmalıdır. sabit. Teşekkürler.
wrobell

1
Yuk. Bu düzeltme gerçekten kafa karıştırıcı. AFAICS, şimdi doğru veya boş değerleri sayacak. Her zaman sahip olmanız için onu yeniden ifade etmenin nullif([boolean expression], false)okumayı çok daha kolay hale getirdiğini düşünüyorum. Daha sonra boolean ifade bölümünü istediğiniz gibi, bu durumda myCol = truedoğru değerleri myCol = falsesaymak veya yanlış değerleri name='john'saymak için veya john vb.
Denen

20

En kısa ve en tembel (dökümsüz) çözüm aşağıdaki formülü kullanmak olacaktır:

SELECT COUNT(myCol OR NULL) FROM myTable;

Kendin dene:

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

ile aynı sonucu verir

SELECT SUM(CASE WHEN x < 7 THEN 1 ELSE 0 END)
   FROM GENERATE_SERIES(0,10) t(x);

Bu kesinlikle benimkinden daha güzel bir çözüm :)
Daniel

Çok anlayışlı cevap.
lucasarruda

7

MySQL'de bunu da yapabilirsiniz:

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

Postgres'te bunun işe yaradığını düşünüyorum:

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

veya daha iyisi (kaçınmak için :: ve standart SQL sözdizimini kullanın):

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

Bu şimdiye kadar gördüğüm en basit çözüm ^ _ ^
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

Ya da belki bu

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;

+1 myColİfade bir boole ise, çekiwhere (myCol)
ypercubeᵀᴹ

üzgünüm, örneğimi fazla basitleştirdim: where cümlesini kullanamıyorum çünkü ayrıca toplam satır sayısını ve gerçek değerlerin sayısını temsil eden bir toplam sayıyı da döndürmek istiyorum.
EoghanM

7

Basitçe boole alanını tam sayıya çevirin ve bir toplam yapın. Bu postgresql üzerinde çalışacaktır:

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

Umarım yardımcı olur!


Diğer çözümlerden ne daha hızlı ne de daha kesin. İnts kullanmak sizin için daha sezgisel olduğu için Oracle'dan geldiğinizi düşünüyorum.
Daniel

4
SELECT count(*)         -- or count(myCol)
FROM   <table name>     -- replace <table name> with your table
WHERE  myCol = true;

Pencereleme Fonksiyonunun bir yolu:

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

-- Outputs:
-- --------------
-- myCol | count
-- ------+-------
--  f    |  2
--  t    |  3
--       |  1

üzgünüm, bu çözümü uyguladığım daha karmaşık örnek için birden çok satır döndüremiyorum.
EoghanM

Evet, ancak ekleyerek daha da kısıtlayabilirsiniz WHERE myCol = true. İkinci örneği daha hızlı olduğu için değil, daha çok Postgres'in pencereleme işlevlerine yönelik eğitici bir parça olarak verdim, ki çoğu kullanıcı bunu rahat hissetmiyor ya da bilmiyor.
vol7ron

0
select count(myCol)
from mytable
group by myCol
;

3 olası bool durumunu (yanlış, doğru, 0) üç satırda gruplayacak, özellikle gün gibi başka bir sütunla birlikte gruplama yaparken kullanışlıdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.