Sql Server эквивалент функции агрегации COUNTIF

Я создаю запрос с предложением GROUP BY, которому нужна возможность подсчитывать записи, основываясь только на определенном условии (например, подсчитывать только записи, где определенное значение столбца равно 1).

SELECT  UID, 
        COUNT(UID) AS TotalRecords, 
        SUM(ContractDollars) AS ContractDollars,
        (COUNTIF(MyColumn, 1) / COUNT(UID) * 100) -- Get the average of all records that are 1
FROM    dbo.AD_CurrentView
GROUP BY UID
HAVING  SUM(ContractDollars) >= 500000

Линия COUNTIF(), очевидно, терпит неудачу, так как нет встроенной функции SQL, называемой COUNTIF, но идея здесь заключается в определении процента всех строк, которые имеют значение "1" для MyColumn.

Любые мысли о том, как правильно реализовать это в среде MS SQL 2005?

Ответ 1

Вы можете использовать SUM (not COUNT!) в сочетании с оператором CASE, например:

SELECT SUM(CASE WHEN myColumn=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView

Примечание: в моем собственном тесте NULL не было проблем, хотя это может быть зависимым от среды. Вы можете обрабатывать нули, например:

SELECT SUM(CASE WHEN ISNULL(myColumn,0)=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView

Ответ 2

Я обычно делаю то, что рекомендовал Джош, но провел мозговой штурм и протестировал слегка хоккейную альтернативу, которую я чувствовал, как совместное использование.

Вы можете воспользоваться тем фактом, что COUNT (ColumnName) не учитывает NULL и использует что-то вроде этого:

SELECT COUNT(NULLIF(0, myColumn))
FROM AD_CurrentView

NULLIF - возвращает NULL, если два значения передаются одинаковыми.

Преимущество: выражает намерение использовать строки COUNT вместо обозначения SUM(). Недостаток: не так ясно, как он работает ( "магия" обычно плохая).

Ответ 3

Я бы использовал этот синтаксис. Он дает то же самое, что и предложения Джоша и Криса, но с этим преимуществом является ANSI и не привязан к конкретному поставщику базы данных.

select count(case when myColumn = 1 then 1 else null end)
from   AD_CurrentView

Ответ 4

Добавление к Josh ответа,

SELECT COUNT(CASE WHEN myColumn=1 THEN AD_CurrentView.PrimaryKeyColumn ELSE NULL END)
FROM AD_CurrentView

Хорошо работает для меня (в SQL Server 2012), не меняя "счет" на "сумму", и та же логика переносима на другие "условные агрегаты". Например, суммирование по условию:

SELECT SUM(CASE WHEN myColumn=1 THEN AD_CurrentView.NumberColumn ELSE 0 END)
FROM AD_CurrentView

Ответ 5

Не зависит от продукта, но стандарт SQL предоставляет

SELECT COUNT() FILTER WHERE <condition-1>, COUNT() FILTER WHERE <condition-2>, ... FROM ...

для этой цели. Или что-то, что близко напоминает его, я не знаю, с верхней части шляпы.

И, конечно же, поставщики предпочтут придерживаться своих собственных решений.

Ответ 6

Почему бы не так?

SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1

Ответ 7

Как насчет

SELECT id, COUNT(IF status=42 THEN 1 ENDIF) AS cnt
FROM table
GROUP BY table

Короче CASE:)

Работает, потому что COUNT() не учитывает нулевые значения, а IF/CASE возвращает null, когда условие не выполняется, и нет ELSE.

Я думаю, что это лучше, чем с помощью SUM().

Ответ 8

Мне пришлось использовать COUNTIF() в моем случае как часть моих столбцов SELECT и имитировать% от количества раз, когда каждый элемент появился в моих результатах.

Итак, я использовал это...

SELECT COL1, COL2, ... ETC
       (1 / SELECT a.vcount 
            FROM (SELECT vm2.visit_id, count(*) AS vcount 
                  FROM dbo.visitmanifests AS vm2 
                  WHERE vm2.inactive = 0 AND vm2.visit_id = vm.Visit_ID 
                  GROUP BY vm2.visit_id) AS a)) AS [No of Visits],
       COL xyz
FROM etc etc

Конечно, вам нужно будет отформатировать результат в соответствии с вашими требованиями к отображению.

Ответ 9

SELECT COALESCE(IF(myColumn = 1,COUNT(DISTINCT NumberColumn),NULL),0) column1,
COALESCE(CASE WHEN myColumn = 1 THEN COUNT(DISTINCT NumberColumn) ELSE NULL END,0) AS column2
FROM AD_CurrentView