postgresql - sql - liczba wartości „true”


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

W powyższej tabeli, jeśli tak:

select count(*), count(myCol);

dostaję 6, 5

Otrzymuję, 5ponieważ nie liczy wpisu zerowego.

Jak policzyć również liczbę prawdziwych wartości (w tym przykładzie 3)?

(To jest uproszczenie i w rzeczywistości używam znacznie bardziej skomplikowanego wyrażenia w funkcji count)

Podsumowanie edycji: chcę również uwzględnić w zapytaniu zwykłą liczbę (*), więc nie mogę użyć klauzuli where


Czy „t” oznacza True anf „f” for False? A może szukasz czegoś takiego jak SELECT COUNT (DISTINCT myCol).
Shamit Verma

spójrz na mój drugi przykład, możesz tam wrzucić, WHERE myCol = truejeśli chcesz, a jeśli usuniesz pierwszy *,, po prostu zwróci liczbę.
vol7ron

@Shamit tak t oznacza prawdę, a f oznacza fałsz, zaktualizowałem pytanie
EoghanM

Równie dobrze możesz nie uprościć swojego pytania / zapytania ... Twoje wymagania ograniczają możliwości lepszej wydajności, a ludzie odpowiadają nieefektywnymi odpowiedziami, które są napotykane bez powodu.
vol7ron

1
@ vol7ron w mojej obronie musi być pewne uproszczenie, aby zadać zrozumiałe pytanie, ale tak, uprościłem zbytnio, kiedy pierwotnie publikowałem.
EoghanM

Odpowiedzi:


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

lub, jak sam się przekonałeś:

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

To dobry hack i otrzymuję ode mnie właściwą odpowiedź. Zgadzam się, chyba że ktoś wymyśli krótsze rozwiązanie?
EoghanM

2
również, czy jest jakiś powód, dla którego zsumowałeś (.. THEN 1 INSE 0) zamiast liczyć (.. THEN true else null)?
EoghanM

5
Nie ... po prostu nie byłem pewien, które wartości będą liczyć () liczyć ... i wiedziałem, że ta suma działa. Ale uwaga: po zastanowieniu uważam, że sum () tylko po wartościach null zwróci null, więc powinno to być COALESCE (sum (...), 0) dla ciebie, lub innymi słowy count () jest lepsze,
Daniel

1
@EoghanM, zobacz krótszą odpowiedź dotyczącą obsady.
Dwayne Towell

1
Możesz faktycznie pominąć, ELSE nullaby uzyskać ten sam wynik.
200_success

91

Rzutuj wartość logiczną na liczbę całkowitą i sumę.

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

Masz 6,3.


3
Plus1: Niezły hack! Jest to prawdopodobnie nawet szybsze niż moje rozwiązanie.
Daniel

1
Jest to najlepsze i najkrótsze rozwiązanie (i ma odpowiedniki w wielu innych środowiskach programistycznych i oprogramowaniu). Powinien być bardziej głosowany

3
„Rzut na int i zliczanie” jest najwyraźniej najbardziej zwięzłe, ale to nie czyni go najlepszym. Nie popierałbym tego, ponieważ podczas gdy wiele środowisk używa reprezentacji 0/1 dla fałszu / prawdy, wiele używa 0 / niezerowych, w tym -1. Zgadzam się, że to „hack”, a rzuty są wystarczająco ryzykowne, gdy nie są „hackami”. Nie będę głosował przeciw, ale znowu nie poprze.
Andrew Wolfe

81

Od PostgreSQL 9.4 istnieje FILTERklauzula , która pozwala na bardzo zwięzłe zapytanie w celu obliczenia prawdziwych wartości:

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

Powyższe zapytanie jest złym przykładem, ponieważ wystarczyłaby prosta klauzula WHERE i służy ona jedynie do zademonstrowania składni. Klauzula FILTER świeci, ponieważ można ją łatwo połączyć z innymi agregatami:

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

Klauzula jest szczególnie przydatna w przypadku agregacji w kolumnie, która używa innej kolumny jako predykatu, umożliwiając jednocześnie pobieranie agregatów filtrowanych w różny sposób w jednym zapytaniu:

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

2
To najlepsza odpowiedź dla PG> 9,4 i jest niesamowicie szybka
Juan Ricardo

47

prawdopodobnie najlepszym podejściem jest użycie funkcji nullif.

ogólnie

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

lub w skrócie

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
Twoje „ogólnie” wygląda nieprawidłowo: AFAICS, nullif([boolean expression], true)zwróci, falsejeśli [wyrażenie logiczne] jest fałszywe, a nulljeśli jest prawdziwe, będziesz liczyć wartości fałszywe. Myślę, że chcesz nullif([boolean expression], false).
rjmunro

tak, „ogólny” przypadek powinien być odwrotny. naprawiony. dzięki.
wrobell

1
Fuj. Ta poprawka jest naprawdę zagmatwana. AFAICS, będzie teraz liczyć wartości true lub null. Myślę, że przeformułowanie go tak, abyś zawsze miał nullif([boolean expression], false), znacznie ułatwia czytanie. Następnie możesz zmienić część wyrażenia boolowskiego, aby była dowolna, w tym przypadku, myCol = trueaby policzyć wartości prawdziwe lub myCol = falsezliczać wartości fałszywe lub name='john'policzyć ludzi zwanych jan itp.
rjmunro

19

Najkrótszym i najbardziej leniwym (bez odlewania) rozwiązaniem byłoby użycie wzoru:

SELECT COUNT(myCol OR NULL) FROM myTable;

Spróbuj sam:

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

daje taki sam wynik jak

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

To zdecydowanie lepsze rozwiązanie niż moje :)
Daniel

Bardzo wnikliwa odpowiedź.
lucasarruda

7

W MySQL możesz to również zrobić:

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

Myślę, że w Postgres to działa:

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

lub lepiej (aby uniknąć :: i użyć standardowej składni SQL):

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

To najprostsze rozwiązanie, jakie kiedykolwiek widziałem ^ _ ^
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

Albo może to

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 Jeśli myColwyrażenie jest wartością logiczną, możesz zamienić czek nawhere (myCol)
ypercubeᵀᴹ

przepraszam, nadmiernie uprościłem mój przykład: nie mogę użyć klauzuli where, ponieważ chcę również zwrócić całkowitą liczbę reprezentującą całkowitą liczbę wierszy, a także liczbę prawdziwych wartości.
EoghanM

7

Po prostu przekonwertuj pole logiczne na liczbę całkowitą i zrób sumę. To zadziała na postgresql:

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

Mam nadzieję, że to pomoże!


Nie jest ani szybszy, ani dokładniejszy niż inne rozwiązania. Uważam, że pochodzisz z Oracle, gdy używanie ints jako wartości logicznej jest dla Ciebie bardziej intuicyjne.
Daniel

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

Oto sposób z funkcją okienkowania:

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

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

przepraszam, nie mogę zwrócić wielu wierszy dla bardziej skomplikowanego przykładu, do którego stosuję to rozwiązanie.
EoghanM

Tak, ale możesz to jeszcze bardziej ograniczyć, po prostu dodając WHERE myCol = true. Podałem drugi przykład nie dlatego, że jest szybszy, ale bardziej jako element edukacyjny dotyczący funkcji okienkowych Postgresa, z którymi wielu użytkowników nie czuje się komfortowo lub o których nie wie.
vol7ron

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

zgrupuje 3 możliwe stany bool (fałsz, prawda, 0) w trzech wierszach, co jest szczególnie przydatne podczas grupowania z inną kolumną, np. dzień

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.