postgresql - sql - recuento de valores `verdaderos`

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

En la tabla anterior, si lo hago:

select count(*), count(myCol);

yo obtengo 6, 5

Obtengo 5ya que no cuenta la entrada nula.

¿Cómo también cuento el número de valores verdaderos (3 en el ejemplo)?

(Esta es una simplificación y en realidad estoy usando una expresión mucho más complicada dentro de la función de conteo)

Editar resumen: también quiero incluir un recuento simple (*) en la consulta, por lo que no puedo usar una cláusula where

EoghanM
fuente
¿La 't' significa Verdadero y la 'f' de Falso? O está buscando algo como SELECT COUNT (DISTINCT myCol).
Shamit Verma
Eche un vistazo a mi segundo ejemplo, puede agregar un WHERE myCol = trueallí si lo desea y si elimina el primero *,, simplemente devolverá el número.
vol7ron
@Shamit sí t significa verdadero y f significa falso, he actualizado la pregunta
EoghanM
Es mejor que no simplifique su pregunta / consulta ... sus requisitos restringen las mejores posibilidades de rendimiento y la gente está respondiendo con respuestas ineficientes, que aumentan sin una buena razón.
vol7ron
1
@ vol7ron en mi defensa tiene que haber alguna simplificación para poder hacer una pregunta comprensible, pero sí, simplifiqué demasiado cuando publiqué originalmente.
EoghanM

Respuestas:

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

o, como lo descubrió por sí mismo:

SELECT count(CASE WHEN myCol THEN 1 END) FROM <table name>
Daniel
fuente
Este es un buen truco y obtiene la respuesta correcta de mi parte. ¿Lo aceptaré a menos que a alguien se le ocurra una solución más breve?
EoghanM
2
además, ¿alguna razón por la que sumaste (.. THEN 1 ELSE 0) en lugar de contar (.. THEN true else null)?
EoghanM
5
No ... es solo que no estaba seguro de qué valores contarían () contar ... y sabía que esa suma funcionaba. Pero cuidado: pensándolo bien, creo que sum () sobre solo valores nulos devolverá nulos, por lo que debería ser COALESCE (sum (...), 0) para usted, o, en otras palabras, count () es mejor,
Daniel
1
@EoghanM, vea la respuesta más corta que involucra al elenco.
Dwayne Towell
1
De hecho, puede omitir ELSE nullobtener el mismo resultado.
200_success
91

Convierte el booleano en un número entero y suma.

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

Usted consigue 6,3.

Dwayne Towell
fuente
3
Plus1: Buen truco! Probablemente esto sea incluso más rápido que mi solución.
Daniel
1
Esta es la mejor y más corta solución (y tiene equivalencias en muchos otros entornos de programación y software). Debería ser votado más
3
El 'reparto para int y contar' es claramente el más conciso, pero eso no lo hace mejor. No respaldaría esto, porque aunque muchos entornos usan la representación 0/1 para falso / verdadero, muchos usan 0 / distinto de cero, incluido -1. Estoy de acuerdo en que es un "truco" y los lanzamientos son lo suficientemente peligrosos cuando no son "trucos". No votará en contra, pero nuevamente, no respaldaría.
Andrew Wolfe
79

Desde PostgreSQL 9.4 existe la FILTERcláusula , que permite una consulta muy concisa para contar los valores verdaderos:

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

La consulta anterior es un mal ejemplo en el sentido de que una simple cláusula WHERE sería suficiente y es solo para demostrar la sintaxis. Donde brilla la cláusula FILTER es que es fácil de combinar con otros agregados:

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

La cláusula es especialmente útil para agregados en una columna que usa otra columna como predicado, mientras que permite obtener agregados filtrados de manera diferente en una sola consulta:

select count(*),
       sum(otherCol) filter (where myCol)
from tbl;
Ilja Everilä
fuente
2
Esta es la mejor respuesta para PG> 9.4 y es increíblemente rápida
Juan Ricardo
47

probablemente, el mejor enfoque es utilizar la función nullif.

en general

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

o en resumen

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
fuente
2
Su "en general" se ve mal: AFAICS, nullif([boolean expression], true)devolverá falsesi [expresión booleana] es falsa, y nullsi es verdadera, entonces estará contando los valores falsos. Creo que quieres nullif([boolean expression], false).
rjmunro
sí, el caso "general" debería ser al revés. fijo. Gracias.
wrobell
1
Puaj. Esa solución es realmente confusa. AFAICS, ahora contará valores verdaderos o nulos. Creo que reformularlo para que siempre lo tengas nullif([boolean expression], false)hace que sea mucho más fácil de leer. A continuación, puede variar la expresión booleana parte de ser lo que quiera, en este caso myCol = truepara contar los verdaderos valores, o myCol = falsepara contar los falsos valores, o name='john'para contar personas llamadas John etc.
rjmunro
19

La solución más corta y perezosa (sin fundición) sería usar la fórmula:

SELECT COUNT(myCol OR NULL) FROM myTable;

Inténtalo tú mismo:

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

da el mismo resultado que

SELECT SUM(CASE WHEN x < 7 THEN 1 ELSE 0 END)
   FROM GENERATE_SERIES(0,10) t(x);
Le Droid
fuente
Esta es definitivamente una solución mejor que la mía :)
Daniel
Respuesta muy perspicaz.
lucasarruda
7

En MySQL, también puede hacer esto:

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

Creo que en Postgres, esto funciona:

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

o mejor (para evitar :: y usar la sintaxis SQL estándar):

SELECT count(*) AS total
     , sum(CAST(myCol AS int)) AS countTrue --convert Boolean to Integer
FROM yourTable
;
ypercubeᵀᴹ
fuente
Esta es la solución más simple que he 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 tal vez esto

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
fuente
+1 Si la myColexpresión es un booleano, puede reemplazar el cheque conwhere (myCol)
ypercubeᵀᴹ
lo siento, simplifiqué demasiado mi ejemplo: no puedo usar una cláusula where ya que también quiero devolver un recuento total que represente el número total de filas, así como un recuento de los valores verdaderos.
EoghanM
7

Simplemente convierta el campo booleano en entero y haga una suma. Esto funcionará en postgresql:

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

¡Espero que ayude!

Jaspreet Singh
fuente
No es ni más rápido ni más preciso que las otras soluciones. Creo que vienes de Oracle cuando usar ints como booleanos es más intuitivo para ti.
Daniel
4
SELECT count(*)         -- or count(myCol)
FROM   <table name>     -- replace <table name> with your table
WHERE  myCol = true;

He aquí una forma con la función de ventana:

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

-- Outputs:
-- --------------
-- myCol | count
-- ------+-------
--  f    |  2
--  t    |  3
--       |  1
vol7ron
fuente
lo siento, no puedo devolver varias filas para el ejemplo más complicado al que estoy aplicando esta solución.
EoghanM
Sí, pero puede restringirlo más simplemente agregando WHERE myCol = true. Proporcioné el segundo ejemplo no porque sea más rápido, sino más como una pieza educativa de las funciones de ventana de Postgres, con las que muchos usuarios no se sienten cómodos o no conocen.
vol7ron
0
select count(myCol)
from mytable
group by myCol
;

agrupará los 3 estados posibles de bool (falso, verdadero, 0) en tres filas especialmente útiles cuando se agrupan con otra columna como día

peligro5000
fuente