Чи можна вказати умову в Count ()?


391

Чи можна вказати умову в Count()? Я хотів би порахувати лише ті рядки, у яких, наприклад, "Менеджер" у стовпці "Позиція".

Я хочу це зробити в операторі count, не використовуючи WHERE; Я питаю про це тому , що мені потрібно розраховувати як менеджер і інші в тому ж SELECT(що - щось на зразок Count(Position = Manager), Count(Position = Other))так WHEREнемає сенсу для мене в цьому прикладі.


4
Будьте всім * користувачам, використовуйте Count (SomeColumnInYourTable), де Position = 'Manager'
Марк Дікінсон

6
@Mark: У всіх сучасних базах даних це не має ніякого значення.
Філіп Лейбаерт

4
@ Марк і Філіп: Насправді це може дуже змінити ситуацію. Якщо поле є нульовим і не індексується, запит повинен торкатися кожного запису в таблиці, тому використання count (*) та count (поле) може дати різні результати та різну продуктивність.
Guffa

3
Я аналізував плани виконання для count (*) vs count (x) протягом багатьох років, і до цих пір не знайшов жодного, який би показав різницю в продуктивності. Ось чому я дуже хотів би побачити приклад запиту, де є різниця.
Філіп Лейбаерт

2
@Matthew: ми не говоримо про це SELECT *, але SELECT COUNT(*)це зовсім інший звір.
Філіп Лейбаерт

Відповіді:


663

Якщо ви не можете просто обмежити сам запит whereпунктом, ви можете використовувати той факт, що countсукупність підраховує лише ненульові значення:

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

Ви також можете використовувати sumагрегат аналогічним чином:

select sum(case Position when 'Manager' then 1 else 0 end)
from ...

що робити, якщо моє поле ціле, і я хочу відповідати нулю. це не працює таким чином, виберіть кількість (випадок IntegerField, коли 'NULL', то ще 1 нульовий кінець) з
Faizan

2
@Faizan null- особливий. Використанняcase when IntegerField is null then ...
Peet Brits

Під час роботи з булевими полями ви можете скористатися цим:SUM(CONVERT(int, IsManager))
Simon_Weaver

2
SQL Server має на увазі формулювання else nullдля caseоператорів, тому count()приклад може бути на 10 символів коротшим (якщо рахувати пробіл).
Майкл - Де Клей Ширкий

212

Якщо припустити, що ви не хочете обмежувати рядки, що повертаються, тому що ви також агрегуєте інші значення, ви можете це зробити так:

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

Скажімо, в тому ж стовпці, у якого були значення менеджера, керівника та керівника команди, ви можете отримати кількість кожного такого:

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 ...

3
@RedFilter Частину навіть не потрібно вказувати else, просто endвідразу після 1.
Денис Валєєв

7
@Denis: правильно - я часто залишаю elseв, оскільки це краще документує результати констатації справи, особливо для нових розробників SQL. Для стислості його можна видалити в цьому випадку.
RedFilter

30

Відповідь @Guffa відмінна, просто зауважте, що, можливо, чистіше з твердженням IF

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

21

Залежить від того, що ви маєте на увазі, але інша інтерпретація сенсу полягає в тому, де ви хочете рахувати рядки з певним значенням, але не хочете обмежуватись SELECTСПОСОБИ ці рядки ...

Ви зробите це за SUM()допомогою пункту в, наприклад, замість цього COUNT(): напр

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

13

Ви також можете використовувати ключове слово Pivot, якщо ви використовуєте SQL 2005 або вище

більше інформації та від Technet

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

Набір даних тесту

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')


4

Я знаю, що це справді старе, але мені подобається NULLIFхитрість для подібних сценаріїв, і я не знайшов жодних недоліків поки. Просто дивіться мій приклад копіювання та вставлення, який не дуже практичний, але демонструє, як ним користуватися.

NULLIF це може дати вам невеликий негативний вплив на продуктивність, але, мабуть, це все-таки має бути швидше, ніж підзапити.

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

Коментарі оцінені :-)



2

Я думаю, ви можете використовувати простий пункт WHERE, щоб вибрати лише підрахунок деякого запису.


Чому я отримую голос "за"? Після того, як я відповів (або може бути той самий час), багато людей відповіли на подібну річ, і вони не отримують жодної протидії. / :(
NawaMan

4
Ви отримуєте зворотну оцінку, оскільки питання "вказуйте умову в підрахунку" НЕ "Порахуйте значення за умовою". Отже, ви відповідаєте на неправильне запитання
Radon8472

3
Трохи несправедливим є зворотне оскарження відповіді, коли відповідь була написана, це було правильним рішенням питання .... він додав зайвий текст через 4 хвилини після цієї відповіді!
Пітер

2

Ось що я зробив для отримання набору даних, який включав як загальну, так і кількість, що відповідали критеріям, у кожному контейнері для доставки. Це дозволить мені відповісти на запитання "Скільки контейнерів для перевезення товарів мають більше X% предметів понад 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


-4

Використовуючи це, ви отримаєте рахунок для менеджерів

Select Position, count(*) as 'Position Counter'
from your_table 
group by Position 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.