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


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>

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.


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;

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


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);

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
;

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;

+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!


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

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.