É possível especificar a condição em Count ()?

392

É possível especificar uma condição em Count()? Gostaria de contar apenas as linhas que possuem, por exemplo, "Gerente" na coluna Posição.

Eu quero fazer isso na instrução count, não usando WHERE; Estou perguntando sobre isso, porque preciso contar os gerentes e os outros da mesma forma SELECT(algo como Count(Position = Manager), Count(Position = Other))isso WHEREnão serve para mim neste exemplo.

agnieszka
fonte
4
Boo a todos os usuários *, Conde uso (SomeColumnInYourTable) onde Position = 'Manager'
Mark Dickinson
6
@ Mark: Em todos os bancos de dados modernos, isso não faz nenhuma diferença.
Philippe Leybaert 9/09/09
5
@ Mark & ​​Philippe: Na verdade, pode fazer uma grande diferença. Se o campo for anulável e não indexado, a consulta precisará tocar em todos os registros da tabela; portanto, o uso de count (*) e count (field) pode fornecer resultados de rede diferentes e desempenho diferente.
Guffa
4
Analisei os planos de execução para contagem (*) vs contagem (x) por anos e, até agora, não encontrei um que mostrasse uma diferença no desempenho. É por isso que eu realmente gostaria de ver um exemplo de consulta em que há uma diferença.
Philippe Leybaert 9/09/09
3
@ Matthew: não estamos falando SELECT *, mas SELECT COUNT(*), que é uma fera totalmente diferente.
Philippe Leybaert 9/09/09

Respostas:

664

Se você não puder limitar a consulta em si com uma wherecláusula, poderá usar o fato de que o countagregado conta apenas os valores não nulos:

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

Você também pode usar o sumagregado de maneira semelhante:

select sum(case Position when 'Manager' then 1 else 0 end)
from ...
Guffa
fonte
e se meu campo for inteiro e eu desejar corresponder nulo. não funciona dessa maneira, selecione count (case IntegerField quando 'NULL' e depois mais 1 final nulo) de
Faizan
2
@Faizan nullé especial. Usecase when IntegerField is null then ...
Peet Brits
Ao trabalhar com campos booleanos, você pode usar o seguinte:SUM(CONVERT(int, IsManager))
Simon_Weaver 04/04
2
O SQL Server implica else nullem caseinstruções for , portanto, o count()exemplo pode ser 10 caracteres menor (se você contar o espaço).
Michael - Onde está Clay Shirky,
213

Supondo que você não deseja restringir as linhas retornadas porque também está agregando outros valores, é possível fazer o seguinte:

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

Digamos que, na mesma coluna, você tenha valores de Gerente, Supervisor e Líder de equipe, você pode obter as contagens de cada um assim:

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
fonte
3
@RedFilter Nem é necessário especificar a elsepeça, apenas enddepois da 1.
Denis Valeev 22/09
7
@ Denis: correto - geralmente deixo o elsedocumento, pois documenta melhor os resultados da declaração de caso, especialmente para desenvolvedores iniciantes de SQL. Por uma questão de brevidade, pode ser removido neste caso.
RedFilter
30

A resposta da @Guffa é excelente, basta apontar que talvez seja mais limpo com uma declaração IF

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

Depende do que você quer dizer, mas a outra interpretação do significado é onde você deseja contar linhas com um determinado valor, mas não deseja restringir o valor SELECT apenas essas linhas ...

Você faria usando SUM()uma cláusula in, assim, em vez de usar COUNT(): por exemplo

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

Você também pode usar a palavra-chave dinâmica, se estiver usando o SQL 2005 ou superior

mais informações e da Technet

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

Conjunto de dados de teste

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

Você quer dizer exatamente isso:

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

Se sim, então sim!

Dana
fonte
11
A edição mostra que ele não deseja restringir as linhas com uma cláusula WHERE
KinSlayerUY
4

Sei que isso é muito antigo, mas gosto do NULLIFtruque para esses cenários e não encontrei desvantagens até agora. Basta ver meu exemplo de cópia e pasta, que não é muito prático, mas demonstra como usá-lo.

NULLIF pode causar um pequeno impacto negativo no desempenho, mas acho que ainda deve ser mais rápido que as 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

Comentários apreciados :-)

z00l
fonte
2
SELECT COUNT(*) FROM bla WHERE Position = 'Manager'
Pedro
fonte
2

Eu acho que você pode usar uma simples cláusula WHERE para selecionar apenas a contagem de algum registro.

NawaMan
fonte
Por que recebo uma votação negativa? Depois que eu respondi (ou pode ser a mesma hora), muitas pessoas responderam a mesma coisa e elas não recebem nenhum voto negativo. / :(
NawaMan 9/09/09
4
Você recebe um voto negativo porque a pergunta é "especificar condição na contagem" NÃO "Contar valores por condição". Então você está respondendo a pergunta errada
Radon8472
3
É um pouco injusto recusar a resposta, quando a resposta foi escrita, foi uma solução correta para a pergunta .... ele adicionou o texto extra 4 minutos após esta resposta!
Peter
2

Aqui está o que fiz para obter um conjunto de dados que incluísse o total e o número que atendiam aos critérios, dentro de cada contêiner de remessa. Deixe-me responder à pergunta "Quantos contêineres de remessa têm mais de X% de itens acima do tamanho 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
user3029478
fonte
-4

Usando isso, você receberá a contagem dos gerentes

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