Можно ли указать условие в Count ()?

392

Можно ли указать условие в Count()? Я хотел бы сосчитать только те строки, которые имеют, например, «Менеджер» в столбце «Позиция».

Я хочу сделать это в подсчете, не используя WHERE; Я спрашиваю об этом, потому что мне нужно считать обоих Менеджеров и Других в одном SELECT(что-то вроде Count(Position = Manager), Count(Position = Other))этого WHEREбесполезно для меня в этом примере.

Агнешка
источник
4
Boo для всех пользователей *, используйте Count (SomeColumnInYourTable), где Position = 'Manager'
Марк Дикинсон
6
@Mark: на всех современных базах данных это не имеет никакого значения.
Филипп Лейберт
5
@Mark & ​​Philippe: На самом деле это может иметь большое значение. Если поле обнуляется и не индексируется, запрос должен касаться каждой записи в таблице, поэтому использование count (*) и count (поле) может дать разные результаты и разную производительность.
Гуффа
4
Я анализировал планы выполнения для count (*) и count (x) в течение многих лет, и до сих пор я не нашел ни одного, который показал бы разницу в производительности. Вот почему мне бы очень хотелось увидеть пример запроса, в котором есть разница.
Филипп Лейберт
3
@ Матфея: мы не говорим SELECT *, но SELECT COUNT(*), это совершенно другой зверь.
Филипп Лейберт

Ответы:

664

Если вы не можете просто ограничить сам запрос 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 ...
Guffa
источник
Что делать, если мое поле является целым числом, и я хочу, чтобы соответствовать нулю. это не работает таким образом выберите счетчик (случай IntegerField, когда 'NULL', а затем еще 1 нулевой конец) из
Faizan
2
@ Файзан nullособенный. Использованиеcase when IntegerField is null then ...
Пит Бритс
При работе с логическими полями вы можете использовать это:SUM(CONVERT(int, IsManager))
Simon_Weaver
2
SQL Server подразумевает операторы else nullfor case, поэтому count()пример может быть на 10 символов короче (если вы посчитаете пробел).
Майкл - Где Клэй Ширки
213

Предполагая, что вы не хотите ограничивать строки, которые возвращаются, потому что вы также агрегируете другие значения, вы можете сделать это следующим образом:

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

Допустим, в том же столбце, где у вас были значения Manager, Supervisor и Team Lead, вы можете получить значения для каждого из них следующим образом:

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
источник
3
@RedFilter Нет необходимости указывать elseдеталь, просто endсразу после 1.
Денис Валеев
7
@Denis: правильно - я часто оставляю elsein, так как он лучше документирует результаты оператора case, особенно для начинающих разработчиков SQL. Для краткости его можно удалить в этом случае.
RedFilter
30

Ответ @Guffa отличный, просто отметьте, что, может быть, чище с заявлением IF

select count(IF(Position = 'Manager', 1, NULL)) as ManagerCount
from ...
Hivenfour
источник
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
AdaTheDev
источник
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')
Мэтью Уайтед
источник
5

Вы имеете в виду именно это:

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

Если так, то да, это работает!

Dana
источник
1
Редактирование показывает, что он не хочет ограничивать строки с помощью предложения WHERE
KinSlayerUY
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

Комментарии приветствуются :-)

z00l
источник
2
SELECT COUNT(*) FROM bla WHERE Position = 'Manager'
Питер
источник
2

Я думаю, что вы можете использовать простое предложение WHERE, чтобы выбрать только подсчет какой-либо записи.

NawaMan
источник
Почему я получаю отрицательный голос? После того, как я ответил (или, может быть, в то же время), многие люди ответили на аналогичную вещь, и они не получают никакого отрицательного голоса. / :(
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
user3029478
источник
1

Обратите внимание, что в PrestoDB SQL (из Facebook) есть ярлык:

https://prestodb.io/docs/current/functions/aggregate.html

count_if (x) → bigint

Возвращает количество ИСТИННЫХ входных значений. Эта функция эквивалентна подсчету (СЛУЧАЙ, КОГДА x ТО 1 КОНЕЦ)

Томас Деко
источник
-4

Используя это, вы получите счет для менеджеров

Select Position, count(*) as 'Position Counter'
from your_table 
group by Position 
Рафаэль
источник