Est-il possible de spécifier une condition dans Count ()?

392

Est-il possible de spécifier une condition dans Count() ? Je voudrais compter uniquement les lignes qui ont, par exemple, "Manager" dans la colonne Position.

Je veux le faire dans l'instruction count, sans utiliser WHERE; Je pose des questions à ce sujet parce que j'ai besoin de compter à la fois les gestionnaires et les autres SELECT(quelque chose comme Count(Position = Manager), Count(Position = Other))ça WHEREne me sert à rien dans cet exemple.

agnieszka
la source
4
Boo à tous les utilisateurs *, utilisez Count (SomeColumnInYourTable) où Position = 'Manager'
Mark Dickinson
6
@Mark: Sur toutes les bases de données modernes, cela ne fait aucune différence.
Philippe Leybaert
5
@Mark & ​​Philippe: En fait, cela peut faire une grande différence. Si le champ est nullable et non indexé, la requête doit toucher chaque enregistrement de la table, donc l'utilisation de count (*) et count (champ) peut donner des résultats différents et des performances différentes.
Guffa
4
J'ai analysé les plans d'exécution pour le nombre (*) par rapport au nombre (x) pendant des années, et jusqu'à présent, je n'en ai trouvé aucun qui montre une différence de performances. C'est pourquoi j'aimerais vraiment voir un exemple de requête où il y a une différence.
Philippe Leybaert
3
@Matthew: nous ne parlons pas de SELECT *, mais SELECT COUNT(*), qui est une bête totalement différente.
Philippe Leybaert

Réponses:

664

Si vous ne pouvez pas simplement limiter la requête elle-même avec une whereclause, vous pouvez utiliser le fait que l' countagrégat compte uniquement les valeurs non nulles:

select count(case Position when 'Manager' then 1 else null end)
from ...

Vous pouvez également utiliser l' sumagrégat de manière similaire:

select sum(case Position when 'Manager' then 1 else 0 end)
from ...
Guffa
la source
que se passe-t-il si mon champ est entier et que je veux correspondre à null. cela ne fonctionne pas de cette façon, sélectionnez count (case IntegerField lorsque 'NULL' puis 1 else null end) de
Faizan
2
@Faizan nullest spécial. Utilisationcase when IntegerField is null then ...
Peet Brits
Lorsque vous travaillez avec des champs booléens, vous pouvez utiliser ceci:SUM(CONVERT(int, IsManager))
Simon_Weaver
2
SQL Server implique une instruction else nullfor case, donc l' count()exemple peut être 10 caractères plus court (si vous comptez l'espace).
Michael - Où est Clay Shirky
213

En supposant que vous ne souhaitez pas restreindre les lignes qui sont retournées car vous agrégez également d'autres valeurs, vous pouvez le faire comme ceci:

select count(case when Position = 'Manager' then 1 else null end) as ManagerCount
from ...

Disons que dans la même colonne que vous aviez des valeurs de Manager, Supervisor et Team Lead, vous pouvez obtenir le nombre de chacun comme ceci:

select count(case when Position = 'Manager' then 1 else null end) as ManagerCount,
    count(case when Position = 'Supervisor' then 1 else null end) as SupervisorCount,
    count(case when Position = 'Team Lead' then 1 else null end) as TeamLeadCount,
from ...
RedFilter
la source
3
@RedFilter Il n'est même pas nécessaire de spécifier la elsepièce, juste endaprès la 1.
Denis Valeev
7
@Denis: correct - je laisse souvent le contenu elsecar il documente mieux les résultats de l'instruction case, en particulier pour les développeurs SQL novices. Par souci de concision, il peut être supprimé dans ce cas.
RedFilter
30

La réponse de @Guffa est excellente, il suffit de souligner que peut-être est plus propre avec une déclaration IF

select count(IF(Position = 'Manager', 1, NULL)) as ManagerCount
from ...
Hivenfour
la source
21

Cela dépend de ce que vous voulez dire, mais l'autre interprétation de la signification est l'endroit où vous voulez compter les lignes avec une certaine valeur, mais ne voulez pas restreindre le SELECT à JUSTE ces lignes ...

Vous le feriez en utilisant SUM()une clause dans, comme ceci au lieu d'utiliser COUNT(): par exemple

SELECT SUM(CASE WHEN Position = 'Manager' THEN 1 ELSE 0 END) AS ManagerCount,
    SUM(CASE WHEN Position = 'CEO' THEN 1 ELSE 0 END) AS CEOCount
FROM SomeTable
AdaTheDev
la source
13

Vous pouvez également utiliser le mot-clé pivot si vous utilisez SQL 2005 ou supérieur

plus d'infos et de Technet

SELECT *
FROM @Users
PIVOT (
    COUNT(Position)
    FOR Position
    IN (Manager, CEO, Employee)
) as p

Ensemble de données de test

DECLARE @Users TABLE (Position VARCHAR(10))
INSERT INTO @Users (Position) VALUES('Manager')
INSERT INTO @Users (Position) VALUES('Manager')
INSERT INTO @Users (Position) VALUES('Manager')
INSERT INTO @Users (Position) VALUES('CEO')
INSERT INTO @Users (Position) VALUES('Employee')
INSERT INTO @Users (Position) VALUES('Employee')
INSERT INTO @Users (Position) VALUES('Employee')
INSERT INTO @Users (Position) VALUES('Employee')
INSERT INTO @Users (Position) VALUES('Employee')
INSERT INTO @Users (Position) VALUES('Employee')
Matthew Whited
la source
5

Voulez-vous dire juste ceci:

SELECT Count(*) FROM YourTable WHERE Position = 'Manager'

Si oui, alors ouais ça marche!

Dana
la source
1
L'édition montre qu'il ne veut pas restreindre les lignes avec une clause WHERE
KinSlayerUY
4

Je sais que c'est vraiment vieux, mais j'aime l' NULLIFastuce pour de tels scénarios, et je n'ai trouvé aucun inconvénient jusqu'à présent. Il suffit de voir mon exemple de copie et de collage, qui n'est pas très pratique cependant, mais montre comment l'utiliser.

NULLIF pourrait vous donner un petit impact négatif sur les performances, mais je suppose que cela devrait toujours être plus rapide que les sous-requêtes.

DECLARE @tbl TABLE ( id [int] NOT NULL, field [varchar](50) NOT NULL)

INSERT INTO @tbl (id, field)
SELECT 1, 'Manager'
UNION SELECT 2, 'Manager'
UNION SELECT 3, 'Customer'
UNION SELECT 4, 'Boss'
UNION SELECT 5, 'Intern'
UNION SELECT 6, 'Customer'
UNION SELECT 7, 'Customer'
UNION SELECT 8, 'Wife'
UNION SELECT 9, 'Son'

SELECT * FROM @tbl

SELECT 
    COUNT(1) AS [total]
    ,COUNT(1) - COUNT(NULLIF([field], 'Manager')) AS [Managers]
    ,COUNT(NULLIF([field], 'Manager')) AS [NotManagers]
    ,(COUNT(1) - COUNT(NULLIF([field], 'Wife'))) + (COUNT(1) - COUNT(NULLIF([field], 'Son'))) AS [Family]
FROM @tbl

Commentaires appréciés :-)

z00l
la source
2
SELECT COUNT(*) FROM bla WHERE Position = 'Manager'
Peter
la source
2

Je pense que vous pouvez utiliser une simple clause WHERE pour sélectionner uniquement le nombre d'enregistrements.

NawaMan
la source
Pourquoi ai-je droit à un vote négatif? Après avoir répondu (ou peut-être en même temps), beaucoup de gens ont répondu à la même chose et ils ne reçoivent aucun vote négatif. / :(
NawaMan
4
Vous obtenez un downvote parce que la question est "spécifier la condition dans Count" PAS "Count values ​​by condition". Vous répondez donc à la mauvaise question
Radon8472
3
C'est un peu injuste de voter contre la réponse, lorsque la réponse a été écrite, c'était une bonne solution à la question .... il a ajouté le texte supplémentaire 4 minutes après cette réponse!
Peter
2

Voici ce que j'ai fait pour obtenir un ensemble de données qui comprenait à la fois le total et le nombre répondant aux critères, dans chaque conteneur d'expédition. Cela m'a permis de répondre à la question "Combien de conteneurs d'expédition ont plus de X% d'articles de plus de 51"

select
   Schedule,
   PackageNum,
   COUNT (UniqueID) as Total,
   SUM (
   case
      when
         Size > 51 
      then
         1 
      else
         0 
   end
) as NumOverSize 
from
   Inventory 
where
   customer like '%PEPSI%' 
group by
   Schedule, PackageNum
user3029478
la source
-4

En utilisant cela, vous obtiendrez le nombre de gestionnaires

Select Position, count(*) as 'Position Counter'
from your_table 
group by Position 
Rafael
la source