¿Es posible especificar la condición en Count ()?

392

¿Es posible especificar una condición en Count() ? Me gustaría contar solo las filas que tienen, por ejemplo, "Administrador" en la columna Posición.

Quiero hacerlo en la declaración de conteo, no usando WHERE; Lo pregunto porque necesito contar tanto a los gerentes como a los demás en el mismo SELECT(algo Count(Position = Manager), Count(Position = Other))así WHEREno me sirve en este ejemplo.

agnieszka
fuente
44
Abuchear a todos los usuarios *, use Count (SomeColumnInYourTable) donde Position = 'Manager'
Mark Dickinson el
66
@ Mark: en todas las bases de datos modernas, esto no hace ninguna diferencia.
Philippe Leybaert
55
@ Mark y Philippe: En realidad, puede hacer una gran diferencia. Si el campo es anulable y no está indexado, la consulta debe tocar todos los registros de la tabla, por lo que el uso de count (*) y count (field) puede proporcionar resultados de red diferentes y un rendimiento diferente.
Guffa
44
He analizado los planes de ejecución para count (*) vs count (x) durante años, y hasta ahora no he encontrado ninguno que muestre una diferencia en el rendimiento. Es por eso que realmente me gustaría ver un ejemplo de una consulta donde hay una diferencia.
Philippe Leybaert
3
@Matthew: no estamos hablando SELECT *, pero SELECT COUNT(*), que es una bestia totalmente diferente.
Philippe Leybaert

Respuestas:

664

Si no puede limitar la consulta en sí con una wherecláusula, puede utilizar el hecho de que el countagregado solo cuenta los valores no nulos:

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

También puede usar el sumagregado de una manera similar:

select sum(case Position when 'Manager' then 1 else 0 end)
from ...
Guffa
fuente
¿Qué pasa si mi campo es entero y quiero coincidir con nulo? no funciona de esta manera, seleccione el recuento (caso IntegerField cuando 'NULL' y luego 1 final nulo) de
Faizan
2
@Faizan nulles especial. Usocase when IntegerField is null then ...
Peet Brits
Al trabajar con campos booleanos puede usar esto:SUM(CONVERT(int, IsManager))
Simon_Weaver
2
SQL Server implica una declaración else nullfor case, por lo que el count()ejemplo puede ser 10 caracteres más corto (si cuenta el espacio).
Michael - ¿Dónde está Clay Shirky?
213

Suponiendo que no desea restringir las filas que se devuelven porque también está agregando otros valores, puede hacerlo así:

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

Digamos que dentro de la misma columna que tenía valores de Gerente, Supervisor y Líder de equipo, podría obtener los recuentos de cada uno de esta manera:

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
fuente
3
@RedFilter Ni siquiera es necesario especificar la elseparte, solo enddespués de la 1.
Denis Valeev
77
@Denis: correcto: a menudo dejo la entrada elseya que documenta mejor los resultados de la declaración del caso, especialmente para los desarrolladores de SQL novatos. Por brevedad, se puede eliminar en este caso.
RedFilter
30

La respuesta de @Guffa es excelente, solo señale que tal vez sea más limpio con una declaración IF

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

Depende de lo que quiera decir, pero la otra interpretación del significado es donde desea contar las filas con un cierto valor, pero no desea restringirlas SELECTa SOLO esas filas ...

Lo harías usando SUM()una cláusula, como esta en lugar de usar COUNT(): ej.

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
fuente
13

También puede usar la palabra clave dinámica si está utilizando SQL 2005 o superior

Más información y de Technet

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

Conjunto de datos de prueba

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
fuente
5

¿Te refieres a esto?

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

Si es así, ¡sí, eso funciona!

Dana
fuente
1
La edición muestra que no quiere restringir las filas con una cláusula WHERE
KinSlayerUY
4

Sé que esto es muy antiguo, pero me gusta el NULLIFtruco para tales escenarios, y hasta ahora no encontré inconvenientes. Solo vea mi ejemplo de copiar y pegar, que no es muy práctico, pero demuestra cómo usarlo.

NULLIF podría darle un pequeño impacto negativo en el rendimiento, pero supongo que aún debería ser más rápido que las subconsultas.

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

Comentarios apreciados :-)

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

Creo que puede usar una simple cláusula WHERE para seleccionar solo el recuento de algunos registros.

NawaMan
fuente
¿Por qué recibo un voto negativo? Después de que respondí (o puede ser al mismo tiempo), muchas personas respondieron algo similar y no reciben ningún voto negativo. / :(
NawaMan
44
Recibes un voto negativo porque la pregunta es "especificar condición en Conteo" NO "Contar valores por condición". Entonces estás respondiendo la pregunta equivocada
Radon8472
3
Es un poco injusto rechazar la respuesta, cuando la respuesta fue escrita fue una solución correcta a la pregunta ... ¡agregó el texto extra 4 minutos después de esta respuesta!
Peter
2

Esto es lo que hice para obtener un conjunto de datos que incluía tanto el total como el número que cumplía los criterios, dentro de cada contenedor de envío. Eso me permite responder la pregunta "¿Cuántos contenedores de envío tienen más del X% de artículos de más del tamaño 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
usuario3029478
fuente
-4

Con esto obtendrás el recuento de gerentes

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