nativas - Servidor SQL equivalente de una función agregada COUNTIF
función de agregación sql server (8)
¿Por qué no me gusta esto?
SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1
Estoy construyendo una consulta con una cláusula GROUP BY
que necesita la capacidad de contar registros basados solo en una determinada condición (por ejemplo, contar solo registros donde un cierto valor de columna es igual a 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 línea COUNTIF()
obviamente falla ya que no hay una función SQL nativa llamada COUNTIF
, pero la idea aquí es determinar el porcentaje de todas las filas que tienen el valor ''1'' para MyColumn.
¿Alguna idea sobre cómo implementar esto correctamente en un entorno MS SQL 2005?
Agregando a la respuesta de Josh,
SELECT COUNT(CASE WHEN myColumn=1 THEN AD_CurrentView.PrimaryKeyColumn ELSE NULL END)
FROM AD_CurrentView
Funcionó bien para mí (en SQL Server 2012) sin cambiar el ''recuento'' a ''suma'' y la misma lógica es portátil para otros ''agregados condicionales''. Por ejemplo, sumando según una condición:
SELECT SUM(CASE WHEN myColumn=1 THEN AD_CurrentView.NumberColumn ELSE 0 END)
FROM AD_CurrentView
No es específico del producto, pero el estándar SQL proporciona
SELECT COUNT() FILTER WHERE <condition-1>, COUNT() FILTER WHERE <condition-2>, ... FROM ...
para este propósito. O algo que se parece mucho a él, no lo sé desde lo alto de mi sombrero.
Y, por supuesto, los proveedores preferirán seguir con sus soluciones patentadas.
Puede usar una SUM
(¡NO COUNT
!) Combinada con una declaración CASE
, como esta:
SELECT SUM(CASE WHEN myColumn=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView
Nota: en mi propia prueba, los NULL
no fueron un problema, aunque esto puede depender del entorno. Podría manejar valores nulos tales como:
SELECT SUM(CASE WHEN ISNULL(myColumn,0)=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView
Qué tal si
SELECT id, COUNT(IF status=42 THEN 1 ENDIF) AS cnt
FROM table
GROUP BY table
Más corto que CASE
:)
Funciona porque COUNT()
no cuenta valores nulos, y IF
/ CASE
devuelve nulo cuando la condición no se cumple y no hay ELSE
.
Creo que es mejor que usar SUM()
.
Tuve que usar COUNTIF () en mi caso como parte de mis columnas SELECT Y para imitar un% de la cantidad de veces que cada elemento apareció en mis resultados.
Entonces usé esto ...
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
Por supuesto, tendrá que formatear el resultado de acuerdo con sus requisitos de visualización.
Usualmente hago lo que Josh me recomendó, pero hice una lluvia de ideas y probé una alternativa ligeramente divertida que me apetecía compartir.
Puede aprovechar el hecho de que COUNT (ColumnName) no cuenta NULL y usa algo como esto:
SELECT COUNT(NULLIF(0, myColumn))
FROM AD_CurrentView
NULLIF - devuelve NULL si los dos valores pasados son los mismos.
Ventaja: Expresa su intención de COUNT filas en lugar de tener la notación SUM (). Desventaja: No está tan claro cómo está funcionando (la "magia" suele ser mala).
Yo usaría esta sintaxis. Obtiene lo mismo que las sugerencias de Josh y Chris, pero con la ventaja de que es compatible con ANSI y no está vinculado a un proveedor de base de datos en particular.
select count(case when myColumn = 1 then 1 else null end)
from AD_CurrentView