191 votes

Equivalent Sql Server d'une fonction agrégée COUNTIF

Je construis une requête avec un GROUP BY qui doit pouvoir compter les enregistrements en fonction d'une certaine condition (par exemple, compter uniquement les enregistrements pour lesquels une certaine valeur de colonne est égale à 1).

SELECT  UID, 
        COUNT(UID) AS TotalRecords, 
        SUM(ContractDollars) AS ContractDollars,
        (COUNTIF(MyColumn, 1) / COUNT(UID) * 100) -- Get the average of all records that are 1
FROM    dbo.AD_CurrentView
GROUP BY UID
HAVING  SUM(ContractDollars) >= 500000

El COUNTIF() échoue évidemment puisqu'il n'y a pas de fonction SQL native appelée COUNTIF mais l'idée ici est de déterminer le pourcentage de toutes les lignes qui ont la valeur '1' pour MaColonne.

Avez-vous des idées sur la manière de mettre en œuvre correctement ce système dans un environnement MS SQL 2005 ?

399voto

JoshBerke Points 34238

Vous pourriez utiliser un SUM (pas COUNT !) combiné à un CASE comme ceci :

SELECT SUM(CASE WHEN myColumn=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView

Note : dans mon propre test NULL n'ont pas été un problème, bien que cela puisse dépendre de l'environnement. Vous pouvez gérer les valeurs nulles de la manière suivante :

SELECT SUM(CASE WHEN ISNULL(myColumn,0)=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView

3 votes

(Je sais que l'OP a posé une question sur MS SQL, mais juste un petit commentaire pour les utilisateurs de SQLite qui font la même chose) SQLite n'a pas d'interface utilisateur. ISNULL Au lieu de cela, vous pouvez faire CASE WHEN myColumn IS NULL ou utiliser ifnull ( stackoverflow.com/a/799406/1861346 )

2 votes

Pouvez-vous expliquer pourquoi sum au lieu de count ?

57voto

Chris Shaffer Points 18066

Je fais habituellement ce que Josh recommande, mais j'ai réfléchi et testé une alternative un peu farfelue que j'ai eu envie de partager.

Vous pouvez profiter du fait que COUNT(ColumnName) ne compte pas les NULLs, et utiliser quelque chose comme ceci :

SELECT COUNT(NULLIF(0, myColumn))
FROM AD_CurrentView

NULLIF - renvoie NULL si les deux valeurs transmises sont identiques.

Avantage : Exprime votre intention de COMPTER les lignes au lieu d'utiliser la notation SUM(). Inconvénient : Le fonctionnement n'est pas aussi clair (la "magie" est généralement mauvaise).

2 votes

Cette solution peut donner une réponse différente de la somme lorsqu'un groupe ne contient que des nuls, ce qui donne 1 au lieu de 0.

0 votes

Vieux poste, mais merci, ça m'a aidé. J'ai étendu la magie et j'ai contourné le problème de "seulement des nulles" en ajoutant ISNULL comme suit : SELECT COUNT(NULLIF(0, ISNULL(myColumn, 0))) . Attends, c'est juste moche...

1 votes

Ce serait parfait s'il existait une fonction NULLIFNOT.

28voto

asgeo1 Points 3336

J'utiliserais cette syntaxe. Elle atteint les mêmes résultats que les suggestions de Josh et Chris, mais avec l'avantage d'être compatible ANSI et de ne pas être liée à un fournisseur de base de données particulier.

select count(case when myColumn = 1 then 1 else null end)
from   AD_CurrentView

2 votes

La réponse de Chris est conforme à la norme SQL (indice : NULLIF est inclus dans la norme SQL-92). La réponse de Josh peut être facilement transformée en Standard SQL en remplaçant isnull con COALESCE .

0 votes

En fait, c'est la réponse que je préfère, car elle reprend l'idée de "compter les rangs" que Chris montrait, mais elle est plus extensible, puisque vous pouvez utiliser n'importe quel opérateur de comparaison ; pas seulement = . Je l'utilise pour "compter le nombre de réponses >=2".

5voto

maf-soft Points 124

Et si

SELECT id, COUNT(IF status=42 THEN 1 ENDIF) AS cnt
FROM table
GROUP BY table

Plus court que CASE :)

Cela fonctionne parce que COUNT() ne compte pas les valeurs nulles, et IF / CASE renvoie null lorsque la condition n'est pas remplie et qu'il n'y a pas de ELSE .

Je pense que c'est mieux que d'utiliser SUM() .

3voto

Sturgus Points 644

Pour compléter la réponse de Josh,

SELECT COUNT(CASE WHEN myColumn=1 THEN AD_CurrentView.PrimaryKeyColumn ELSE NULL END)
FROM AD_CurrentView

Cela a bien fonctionné pour moi (dans SQL Server 2012) sans changer le 'count' en 'sum' et la même logique est portable à d'autres 'agrégats conditionnels'. Par exemple, additionner en fonction d'une condition :

SELECT SUM(CASE WHEN myColumn=1 THEN AD_CurrentView.NumberColumn ELSE 0 END)
FROM AD_CurrentView

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X