postgresql - sql - nombre de valeurs `true`

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

Dans le tableau ci-dessus, si je le fais:

select count(*), count(myCol);

Je reçois 6, 5

J'obtiens 5car il ne compte pas l'entrée nulle.

Comment compter également le nombre de valeurs vraies (3 dans l'exemple)?

(Ceci est une simplification et j'utilise en fait une expression beaucoup plus compliquée dans la fonction de comptage)

Modifier le résumé: je souhaite également inclure un nombre brut (*) dans la requête, je ne peux donc pas utiliser de clause where

EoghanM
la source
Est-ce que «t» signifie True et «f» signifie False? Ou cherchez-vous quelque chose comme SELECT COUNT (DISTINCT myCol).
Shamit Verma
jetez un œil à mon deuxième exemple, vous pouvez y ajouter un WHERE myCol = truesi vous le souhaitez et si vous supprimez le premier, *,il renverra simplement le numéro.
vol7ron
@Shamit yes t signifie vrai, et f signifie faux, j'ai mis à jour la question
EoghanM
Vous pourriez tout aussi bien ne pas simplifier votre question / requête ... vos exigences limitent les meilleures possibilités de performances et les gens répondent avec des réponses inefficaces, qui se retrouvent sans raison.
vol7ron
1
@ vol7ron pour ma défense, il doit y avoir une certaine simplification afin de poser une question compréhensible, mais oui, j'ai trop simplifié lorsque j'ai publié initialement.
EoghanM

Réponses:

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

ou, comme vous l'avez découvert vous-même:

SELECT count(CASE WHEN myCol THEN 1 END) FROM <table name>
Daniel
la source
C'est un bon hack et obtient la bonne réponse de ma part. Je l'accepterai à moins que quelqu'un ne propose une solution plus courte?
EoghanM
2
aussi, une raison pour laquelle vous avez fait la somme (.. ALORS 1 ELSE 0) au lieu de compter (.. ALORS vrai sinon nul)?
EoghanM
5
Non ... c'est juste que je n'étais pas sûr de savoir quelles valeurs compteraient () compter ... et je savais que cette somme faisait l'affaire. Mais attention: à la réflexion, je crois que sum () sur seulement les valeurs nulles renverra null, donc ce devrait être COALESCE (sum (...), 0) pour vous, ou, en d'autres termes, count () est meilleur,
Daniel
1
@EoghanM, voir la réponse plus courte concernant le casting.
Dwayne Towell
1
Vous pouvez en fait omettre ELSE nullpour obtenir le même résultat.
200_success
91

Convertissez le booléen en entier et en somme.

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

Vous obtenez 6,3.

Serviette Dwayne
la source
3
Plus1: Nice hack! C'est probablement encore plus rapide que ma solution.
Daniel
1
C'est la meilleure et la plus courte solution (et a des équivalences dans de nombreux autres environnements de programmation et logiciels). Devrait être voté plus
3
Le 'cast to int and count' est clairement le plus concis, mais cela ne le rend pas meilleur. Je n'approuverais pas cela, car si de nombreux environnements utilisent la représentation 0/1 pour faux / vrai, beaucoup utilisent 0 / non-zéro, y compris -1. Je suis d'accord que c'est un "hack", et les lancers sont assez risqués quand ils ne sont pas des "hacks". Je ne voterai pas mais encore une fois, je n'approuverai pas.
Andrew Wolfe
79

Depuis PostgreSQL 9.4, il y a la FILTERclause , qui permet une requête très concise pour compter les vraies valeurs:

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

La requête ci-dessus est un mauvais exemple dans la mesure où une simple clause WHERE suffirait, et sert uniquement à démontrer la syntaxe. Là où la clause FILTER brille, c'est qu'il est facile de la combiner avec d'autres agrégats:

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

La clause est particulièrement pratique pour les agrégats sur une colonne qui utilise une autre colonne comme prédicat, tout en permettant de récupérer des agrégats filtrés différemment dans une seule requête:

select count(*),
       sum(otherCol) filter (where myCol)
from tbl;
Ilja Everilä
la source
2
C'est la meilleure réponse pour PG> 9,4 et est incroyablement rapide
Juan Ricardo
47

probablement, la meilleure approche consiste à utiliser la fonction nullif.

en général

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

ou en bref

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
la source
2
Votre "en général" semble faux: AFAICS, nullif([boolean expression], true)retournera falsesi [expression booléenne] est fausse, et nullsi elle est vraie, vous compterez donc les fausses valeurs. Je pense que tu veux nullif([boolean expression], false).
rjmunro
oui, le cas «général» devrait être l'inverse. fixé. Merci.
wrobell
1
Yuk. Ce correctif est vraiment déroutant. AFAICS, il comptera désormais les valeurs vraies ou nulles. Je pense que le reformuler de manière à ce que vous l'ayez toujours nullif([boolean expression], false)fait en sorte qu'il soit beaucoup plus facile à lire. Vous pouvez ensuite faire varier la partie de l'expression booléenne pour qu'elle soit ce que vous voulez, dans ce cas myCol = truepour compter les vraies valeurs, ou myCol = falsepour compter les fausses valeurs, ou name='john'pour compter les personnes appelées john etc.
rjmunro
19

La solution la plus courte et la plus paresseuse (sans coulée) serait d'utiliser la formule:

SELECT COUNT(myCol OR NULL) FROM myTable;

Essayez-le vous-même:

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

donne le même résultat que

SELECT SUM(CASE WHEN x < 7 THEN 1 ELSE 0 END)
   FROM GENERATE_SERIES(0,10) t(x);
Le Droid
la source
C'est certainement une meilleure solution que la mienne :)
Daniel
Réponse très perspicace.
lucasarruda
7

Dans MySQL, vous pouvez également le faire:

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

Je pense que dans Postgres, cela fonctionne:

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

ou mieux (pour éviter :: et utiliser la syntaxe SQL standard):

SELECT count(*) AS total
     , sum(CAST(myCol AS int)) AS countTrue --convert Boolean to Integer
FROM yourTable
;
ypercubeᵀᴹ
la source
C'est la solution la plus simple que j'aie jamais vue ^ _ ^
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

Ou peut-être ceci

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
la source
+1 Si l' myColexpression est un booléen, vous pouvez remplacer la vérification parwhere (myCol)
ypercubeᵀᴹ
désolé, j'ai trop simplifié mon exemple: je ne peux pas utiliser une clause where car je souhaite également renvoyer un nombre total représentant le nombre total de lignes, ainsi qu'un nombre des vraies valeurs.
EoghanM
7

Convertissez simplement le champ booléen en entier et faites une somme. Cela fonctionnera sur postgresql:

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

J'espère que cela pourra aider!

Jaspreet Singh
la source
Ce n'est ni plus rapide ni plus précis que les autres solutions. Je crois que vous venez d'Oracle lorsque l'utilisation des ints comme booléen est plus intuitive pour vous.
Daniel
4
SELECT count(*)         -- or count(myCol)
FROM   <table name>     -- replace <table name> with your table
WHERE  myCol = true;

Voici un moyen avec la fonction de fenêtrage:

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

-- Outputs:
-- --------------
-- myCol | count
-- ------+-------
--  f    |  2
--  t    |  3
--       |  1
vol7ron
la source
désolé, je ne peux pas renvoyer plusieurs lignes pour l'exemple plus compliqué auquel j'applique cette solution.
EoghanM
Oui, mais vous pouvez le restreindre davantage en ajoutant simplement WHERE myCol = true. J'ai fourni le deuxième exemple non pas parce qu'il est plus rapide, mais plutôt comme un élément pédagogique sur les fonctions de fenêtrage de Postgres, que de nombreux utilisateurs ne sont pas à l'aise ou ne connaissent pas.
vol7ron
0
select count(myCol)
from mytable
group by myCol
;

regroupera les 3 états possibles de bool (false, true, 0) en trois lignes particulièrement pratique lors du regroupement avec une autre colonne comme day

danger5000
la source