2009-02-24 8 views
123

Estoy creando 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).Servidor sql equivalente de una función de agregado COUNTIF

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 de COUNTIF() obviamente falla ya que no hay función SQL nativo llamado COUNTIF, pero la idea aquí es determinar el porcentaje de todas las filas que tienen el valor '1' para MiColumna.

¿Alguna idea sobre cómo implementar esto correctamente en un entorno MS SQL 2005?

Respuesta

241

Se puede usar un SUM (no COUNT!) Combinado con una declaración CASE, así:

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

Nota: en mi propia prueba NULL s no eran un problema, aunque esto puede ser dependientes del entorno. Se podía manejar los nulos tales como:

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

(Sé que OP preguntó acerca de MS SQL, pero solo un pequeño comentario para usuarios de SQLite que hacen lo mismo) SQLite no tiene 'ISNULL', en su lugar puedes hacer' CASE WHEN myColumn IS NULL', o usar 'ifnull' (https://stackoverflow.com/a/799406/1861346) – Matt

43

que suele hacer lo que Josh recomendable, pero una lluvia de ideas y probó una alternativa un poco hokey que me sentí como el compartir.

Usted puede aprovechar el hecho de que COUNT (ColumnName) no cuenta valores nulos, y usar algo como esto:

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

NULLIF - devuelve NULL si los dos valores en el pasado 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 funciona ("magia" suele ser malo).

+2

Esta solución puede dar respuestas diferentes a la suma cuando un grupo solo contiene nulos resulta en 1 en lugar de 0. – KimvdLinde

+0

Publicación anterior, pero gracias a esto ayudó. Extendí la magia y solucioné el problema de "solo nulos" al agregar 'ISNULL' de la siguiente manera:' SELECT COUNT (NULLIF (0, ISNULL (myColumn, 0))) '. Espere, eso se ve feo ... – pcdev

16

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

La respuesta de Chris es conforme a SQL estándar (sugerencia: 'NULLIF' se incluye con el estándar SQL-92). La respuesta de Josh se puede transformar fácilmente en SQL estándar reemplazando 'isnull' con' COALESCE'. – onedaywhen

+0

En realidad, me gusta esta respuesta, porque tiene la idea de "contar filas" que Chris mostraba, pero es más extensible, ya que puedes usar cualquier operador de comparación; no solo '='. Lo estoy usando para "contar el número de respuestas> = 2". –

0

no referida a productos específicos, 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.

+1

Nunca había oído hablar de esto antes, así que lo busqué. Según http://modern-sql.com/feature/filter, el único DBMS importante que ofrece la cláusula 'FILTER' es PostgreSQL, pero está emulado por' CASE' en todos ellos. –

0

¿Por qué no me gusta?

SELECT count(1) 
FROM AD_CurrentView 
WHERE myColumn=1 
+0

Porque necesita mucho más que solo el conteo. Está tratando de obtener recuento de una parte de un grupo, y luego un agregado de todo el grupo, que no se puede hacer con un DÓNDE. –

1

la adición a la respuesta de Josh,

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

funcionado bien para mí (en SQL Server 2012) sin cambiar el 'contar' a una 'suma' y la misma lógica es portátil a otra ' agregados condicionales '. P.ej., Sumando en base a una condición:

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

¿Qué tal

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 los valores nulos, y IF/CASE nula devuelto cuando la condición no se cumple y no hay ELSE.

Creo que es mejor que usar SUM().

0

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.

por lo que utiliza este ...

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 que tendrá que formatear el resultado de acuerdo a sus necesidades de visualización.

Cuestiones relacionadas