postgresql - sql - conteggio dei valori "true"


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

Nella tabella sopra, se lo faccio:

select count(*), count(myCol);

ottengo 6, 5

Ottengo 5perché non conta la voce nulla.

Come faccio a contare anche il numero di valori veri (3 nell'esempio)?

(Questa è una semplificazione e in realtà sto usando un'espressione molto più complicata all'interno della funzione count)

Modifica riepilogo: voglio anche includere un conteggio normale (*) nella query, quindi non posso utilizzare una clausola where


"T" sta per True e "f" per False? Oppure stai cercando qualcosa come SELECT COUNT (DISTINCT myCol).
Shamit Verma

dai un'occhiata al mio secondo esempio, puoi inserire un WHERE myCol = truese vuoi e se rimuovi il primo *,restituirà solo il numero.
vol7ron

@Shamit sì t sta per vero e f sta per falso, ho aggiornato la domanda
EoghanM

Potresti anche non semplificare la tua domanda / query ... i tuoi requisiti limitano le migliori possibilità di prestazioni e le persone rispondono con risposte inefficienti, che vengono urtate senza una buona ragione.
vol7ron

1
@ vol7ron in mia difesa ci deve essere una semplificazione per porre una domanda comprensibile, ma sì, ho semplificato eccessivamente quando ho postato originariamente.
EoghanM

Risposte:


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

oppure, come hai scoperto tu stesso:

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

Questo è un buon trucco e da me ottiene la risposta giusta. Lo accetterò a meno che qualcuno non proponga una soluzione più breve?
EoghanM

2
inoltre, qualche motivo per cui hai sommato (.. THEN 1 ELSE 0) invece di count (.. THEN true else null)?
EoghanM

5
No ... è solo che non ero sicuro di quali valori avrebbero contato () ... e sapevo che la somma ha funzionato. Ma attenzione: a pensarci bene, credo che sum () solo su valori nulli restituirà null, quindi dovrebbe essere COALESCE (sum (...), 0) per te, o, in altre parole, count () è meglio,
Daniel

1
@EoghanM, vedi risposta più breve che coinvolge il cast.
Dwayne Towell

1
Puoi effettivamente omettere ELSE nullper ottenere lo stesso risultato.
200_success

91

Converti il ​​valore booleano su un numero intero e somma.

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

Ottieni 6,3.


3
Plus1: bel trucco! Questo è probabilmente anche più veloce della mia soluzione.
Daniel

1
Questa è la soluzione migliore e più breve (e ha equivalenze in molti altri ambienti di programmazione e software). Dovrebbe essere votato di più

3
Il "cast to int and count" è chiaramente il più conciso, ma questo non lo rende migliore. Non lo approvo, perché mentre molti ambienti usano la rappresentazione 0/1 per falso / vero, molti usano 0 / diverso da zero, incluso -1. Sono d'accordo che sia un "hack" e i cast sono abbastanza rischiosi quando non sono "hack". Non voterò negativamente ma, ancora una volta, non avallo.
Andrew Wolfe,

79

Da PostgreSQL 9.4 c'è la FILTERclausola , che consente una query molto concisa per contare i valori veri:

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

La query precedente è un cattivo esempio in quanto una semplice clausola WHERE sarebbe sufficiente e serve solo per dimostrare la sintassi. Dove brilla la clausola FILTER è che è facile da combinare con altri aggregati:

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

La clausola è particolarmente utile per le aggregazioni su una colonna che utilizza un'altra colonna come predicato, consentendo al contempo di recuperare aggregazioni filtrate in modo diverso in una singola query:

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

2
Questa è la migliore risposta per PG> 9.4 ed è incredibilmente veloce
Juan Ricardo

47

probabilmente l'approccio migliore è usare la funzione nullif.

in generale

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

o in breve

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
Il tuo "in generale" sembra sbagliato: AFAICS, nullif([boolean expression], true)restituirà falsese [espressione booleana] è falso, e nullse è vero, quindi conterai i valori falsi. Penso che tu voglia nullif([boolean expression], false).
rjmunro

sì, il caso "generale" dovrebbe essere il contrario. fisso. Grazie.
wrobell

1
Che schiffo. Quella correzione è davvero confusa. AFAICS, ora conterà valori veri o nulli. Penso che riformularlo in modo da avere sempre nullif([boolean expression], false)lo rende molto più facile da leggere. Puoi quindi variare la parte dell'espressione booleana in modo che sia quello che preferisci, in questo caso myCol = trueper contare i valori veri o myCol = falseper contare i valori falsi, o name='john'per contare le persone chiamate john ecc.
rjmunro

19

La soluzione più breve e più pigra (senza casting) sarebbe usare la formula:

SELECT COUNT(myCol OR NULL) FROM myTable;

Provate voi stessi:

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

dà lo stesso risultato di

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

Questa è sicuramente una soluzione più carina della mia :)
Daniel

Risposta molto perspicace.
lucasarruda

7

In MySQL, puoi fare anche questo:

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

Penso che in Postgres funzioni:

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

o meglio (per evitare :: e utilizzare la sintassi SQL standard):

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

Questa è la soluzione più semplice che abbia mai visto ^ _ ^
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

O forse questo

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 Se l' myColespressione è un booleano, puoi sostituire il segno di spunta conwhere (myCol)
ypercubeᵀᴹ

scusate ho semplificato eccessivamente il mio esempio: non posso utilizzare una clausola where perché desidero anche restituire un conteggio totale che rappresenta il numero totale di righe, nonché un conteggio dei valori reali.
EoghanM

7

Converti semplicemente il campo booleano in numero intero e fai una somma. Questo funzionerà su postgresql:

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

Spero che aiuti!


Non è né più veloce né più preciso delle altre soluzioni. Credo che vieni da Oracle quando usi int come booleano è più intuitivo per te.
Daniel,

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

Ecco un modo con la funzione Windowing:

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

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

scusa non posso restituire più righe per l'esempio più complicato a cui sto applicando questa soluzione.
EoghanM

Sì, ma puoi limitarlo ulteriormente semplicemente aggiungendo WHERE myCol = true. Ho fornito il secondo esempio non perché è più veloce, ma più come un pezzo educativo per le funzioni di finestre di Postgres, con cui molti utenti non sono a proprio agio o non conoscono.
vol7ron

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

raggrupperà i 3 possibili stati di bool (false, true, 0) in tre righe particolarmente utili quando si raggruppano insieme a un'altra colonna come il giorno

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.