Je construis une requête avec une clause GROUP BY
qui nécessite la possibilité de compter les enregistrements uniquement en fonction d'une condition donnée (par exemple, ne comptabiliser que les enregistrements pour lesquels la valeur d'une 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
La ligne COUNTIF()
échoue évidemment car il n’existe pas de fonction SQL native appelée COUNTIF
, mais l’idée ici est de déterminer le pourcentage de toutes les lignes ayant la valeur «1» pour MyColumn.
Avez-vous des idées sur la manière de mettre en œuvre correctement cela dans un environnement MS SQL 2005?
Vous pouvez utiliser un SUM
(pas COUNT
!) Combiné avec une instruction CASE
, comme ceci:
SELECT SUM(CASE WHEN myColumn=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView
Remarque: dans mon propre test, NULL
s n'était pas un problème, bien que cela puisse dépendre de l'environnement. Vous pouvez gérer des valeurs nulles telles que:
SELECT SUM(CASE WHEN ISNULL(myColumn,0)=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView
Je fais habituellement ce que Josh avait recommandé, mais j'ai fait un brainstorming et testé une alternative légèrement hokey que j'avais envie de partager.
Vous pouvez tirer parti du fait que COUNT (ColumnName) ne compte pas les valeurs NULL et utilisez 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 de la notation SUM () . Inconvénient: son fonctionnement n'est pas aussi clair (la "magie" est généralement mauvaise).
Je voudrais utiliser cette syntaxe. Cela répond aux suggestions de Josh et Chris, mais avec l'avantage, il est compatible ANSI et n'est pas lié à un fournisseur de base de données particulier.
select count(case when myColumn = 1 then 1 else null end)
from AD_CurrentView
Ajoutant à la réponse de Josh,
SELECT COUNT(CASE WHEN myColumn=1 THEN AD_CurrentView.PrimaryKeyColumn ELSE NULL END)
FROM AD_CurrentView
A bien fonctionné pour moi (dans SQL Server 2012) sans changer le "compte" en "somme" et la même logique est transférable vers d'autres "agrégats conditionnels". Exemple: sommation basée sur une condition:
SELECT SUM(CASE WHEN myColumn=1 THEN AD_CurrentView.NumberColumn ELSE 0 END)
FROM AD_CurrentView
Pourquoi pas comme ça?
SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1
Que diriez-vous
SELECT id, COUNT(IF status=42 THEN 1 ENDIF) AS cnt
FROM table
GROUP BY table
Plus court que CASE
:)
Fonctionne parce que COUNT()
ne compte pas les valeurs null et que 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()
.
J'ai dû utiliser COUNTIF () dans mon cas dans le cadre de mes colonnes SELECT ET pour imiter un% du nombre de fois où chaque élément est apparu dans mes résultats.
Alors j'ai utilisé ça ...
SELECT COL1, COL2, ... ETC
(1 / SELECT a.vcount
FROM (SELECT vm2.visit_id, count(*) AS vcount
FROM dbo.visitmanifests AS vm2
WHERE vm2.inactive = 0 AND vm2.visit_id = vm.Visit_ID
GROUP BY vm2.visit_id) AS a)) AS [No of Visits],
COL xyz
FROM etc etc
Bien entendu, vous devrez formater le résultat en fonction de vos besoins d'affichage.
Pas spécifique au produit, mais le standard SQL fournit
SELECT COUNT() FILTER WHERE <condition-1>,
COUNT() FILTER WHERE <condition-2>, ...
FROM ...
dans ce but. Ou quelque chose qui lui ressemble de près, je ne le sais pas du tout.
Et bien sûr, les fournisseurs préféreront s'en tenir à leurs solutions propriétaires.