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?

Ответов (9)

Решение

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

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

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

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

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

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

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

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

для этого. Или что-то, что очень похоже на это, я не знаю наверняка.

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

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

SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1

Добавляя к ответу Джоша,

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

Как насчет

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

Короче CASE :)

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

Думаю, это лучше, чем использовать SUM() .

Мне пришлось использовать 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

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

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

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

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

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

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

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