Czy można określić warunek w Count ()?

391

Czy można określić warunek w Count()? Chciałbym policzyć tylko wiersze, które mają na przykład „Menedżer” w kolumnie Pozycja.

Chcę to zrobić w instrukcji count, nie używając WHERE; Pytam o to, ponieważ muszę policzyć zarówno menedżerów, jak i innych w tym samymSELECT (coś jak Count(Position = Manager), Count(Position = Other))więc WHEREnie ma sensu dla mnie w tym przykładzie.

agnieszka
źródło
4
Boo dla wszystkich * użytkowników, użyj Count (SomeColumnInYourTable) gdzie Position = 'Manager'
Mark Dickinson
6
@ Mark: We wszystkich nowoczesnych bazach danych nie ma to żadnej różnicy.
Philippe Leybaert
4
@Mark & ​​Philippe: W rzeczywistości może to być wielka różnica. Jeśli pole ma wartość zerową i nie jest indeksowane, zapytanie musi dotykać każdego rekordu w tabeli, więc użycie count (*) i count (field) może dać różne wyniki i inną wydajność.
Guffa,
3
Przez lata analizowałem plany wykonania dla count (*) vs. count (x) i do tej pory nie znalazłem żadnego, który wykazałby różnicę w wydajności. Dlatego naprawdę chciałbym zobaczyć przykład zapytania, w którym jest różnica.
Philippe Leybaert
2
@Matthew: Nie mówimy o tym SELECT *, ale SELECT COUNT(*), co jest zupełnie inną bestią.
Philippe Leybaert

Odpowiedzi:

663

Jeśli nie możesz po prostu ograniczyć samego zapytania za pomocą whereklauzuli, możesz użyć faktu, że countagregat liczy tylko wartości inne niż null:

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

Możesz także użyć sumagregatu w podobny sposób:

select sum(case Position when 'Manager' then 1 else 0 end)
from ...
Guffa
źródło
co jeśli moje pole jest liczbą całkowitą i chcę dopasować null. to nie działa w ten sposób wybierz liczbę (przypadek IntegerField, gdy „NULL”, a następnie 1 else null end) z
Faizan
2
@Faizan nulljest wyjątkowy. Użyjcase when IntegerField is null then ...
Peet Brits,
Podczas pracy z polami logicznymi możesz użyć tego:SUM(CONVERT(int, IsManager))
Simon_Weaver 4.04.17
2
SQL Server sugeruje instrukcję else nullfor case, więc count()przykład może mieć 10 znaków krótszy (jeśli policzysz spację).
Michael - Where's Clay Shirky
212

Zakładając, że nie chcesz ograniczać zwracanych wierszy, ponieważ agregujesz również inne wartości, możesz to zrobić w następujący sposób:

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

Powiedzmy, że w tej samej kolumnie, w której masz wartości Menedżera, Przełożonego i Kierownika zespołu, możesz uzyskać liczby takich jak poniżej:

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
źródło
3
@ RedFilter Nie jest nawet konieczne określenie elseczęści, wystarczy endją zaraz po 1.
Denis Valeev
7
@Denis: poprawne - często zostawiam wpis, elseponieważ lepiej dokumentuje wyniki instrukcji case, szczególnie dla początkujących programistów SQL. Dla zwięzłości można go w tym przypadku usunąć.
RedFilter
30

Odpowiedź @ Guffa jest doskonała, po prostu zwróć uwagę, że może jest czystsza dzięki stwierdzeniu IF

select count(IF(Position = 'Manager', 1, NULL)) as ManagerCount
from ...
Hivenfour
źródło
21

Zależy, co masz na myśli, ale inna interpretacja znaczenia polega na tym, że chcesz liczyć wiersze o określonej wartości, ale nie chcesz ograniczać SELECT do TYLKO tych wierszy ...

Zrobiłbyś to używając SUM()klauzuli w, takiej jak ta zamiast używania COUNT(): np

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
źródło
13

Możesz także użyć słowa kluczowego przestawnego, jeśli używasz SQL 2005 lub nowszego

więcej informacji i od Technet

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

Zestaw danych testowych

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
źródło
5

Masz na myśli tylko to:

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

Jeśli tak, to działa!

Dana
źródło
1
Edycja pokazuje, że nie chce ograniczać wierszy klauzulą ​​WHERE
KinSlayerUY
4

Wiem, że to naprawdę stare, ale podoba mi się NULLIFsztuczka w takich scenariuszach i jak dotąd nie znalazłem żadnych wad. Zobacz mój przykład do skopiowania i wklejenia, który nie jest zbyt praktyczny, ale pokazuje, jak go używać.

NULLIF może mieć niewielki negatywny wpływ na wydajność, ale myślę, że nadal powinno być szybsze niż podzapytania.

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

Komentarze mile widziane :-)

z00l
źródło
2
SELECT COUNT(*) FROM bla WHERE Position = 'Manager'
Piotr
źródło
2

Myślę, że możesz użyć prostej klauzuli WHERE, aby wybrać tylko policz rekord.

NawaMan
źródło
Dlaczego dostaję głos negatywny? Po tym, jak odpowiedziałem (lub może być w tym samym czasie), wiele osób odpowiedziało na to samo i nie otrzymało żadnego negatywnego wyniku. / :(
NawaMan
4
Otrzymujesz opinię negatywną, ponieważ pytanie brzmi: „określ warunek w policzeniu” NIE „policz wartości według warunku”. Odpowiadasz więc na złe pytanie
Radon8472,
3
Głosowanie za odpowiedzią jest trochę niesprawiedliwe, kiedy odpowiedź była napisana, było to prawidłowe rozwiązanie pytania ... dodał dodatkowy tekst 4 minuty po tej odpowiedzi!
Peter,
2

Oto, co zrobiłem, aby uzyskać zestaw danych zawierający zarówno sumę, jak i liczbę spełniającą kryteria, w każdym kontenerze wysyłkowym. To pozwala mi odpowiedzieć na pytanie „Ile kontenerów zawiera więcej niż X% produktów powyżej rozmiaru 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
użytkownik3029478
źródło
-4

Korzystając z tego, otrzymasz liczbę menedżerów

Select Position, count(*) as 'Position Counter'
from your_table 
group by Position 
Rafael
źródło