Еквівалент сервера Sql функції агрегації COUNTIF


164

Я будую запит із 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?

Відповіді:


339

Ви можете використовувати SUM(не 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

3
(Я знаю, що ОП запитував про MS SQL, але лише крихітний коментар для користувачів SQLite, які роблять те саме). У SQLite немає ISNULL, натомість ви можете робити CASE WHEN myColumn IS NULLабо використовувати ifnull( stackoverflow.com/a/799406/1861346 )
Метт,

54

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

Ви можете скористатися тим, що COUNT (ColumnName) не рахує NULL, і використовувати щось подібне:

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

NULLIF - повертає NULL, якщо два передані значення однакові.

Перевага: висловлює свій намір COUNT рядків, а не позначення SUM (). Недолік: Не так зрозуміло, як це працює ("магія" зазвичай погана).


2
Це рішення може дати інші відповіді, ніж сума, коли група містить лише нулі, це призводить до 1, а не до 0.
KimvdLinde

Старий пост, але спасибі це допомогло. Я продовжив магії і отримав навколо «тільки NULLS» проблему шляхом додавання ISNULLнаступним чином : SELECT COUNT(NULLIF(0, ISNULL(myColumn, 0))). Зачекайте, це просто виглядає потворно ...
pcdev

1
Було б ідеально, якби була функція
NULLIFNOT

21

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

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

2
Відповідь Кріса відповідає стандарту Stndard SQL (підказка: NULLIFвходить Standard SQL-92). Відповідь Джоша можна легко перетворити на Standard SQL, замінивши isnullна COALESCE.
день, коли

Мені справді найбільше подобається ця відповідь, оскільки вона отримує уявлення про "підрахунок рядків", який показав Кріс, але є більш розширеним, оскільки ви можете використовувати будь-якого оператора порівняння; не просто =. Я використовую це для "підрахунку кількості відповідей> = 2".
Крістен Хаммак

3

Додавши до відповіді Джоша,

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

Добре працював для мене (у SQL Server 2012), не змінюючи значення 'count' на 'sum' і така ж логіка переноситься на інші 'умовні агрегати'. Напр., Підсумовуючи на основі умови:

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

2

Як щодо

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

Коротше CASE :)

Працює, оскільки COUNT()не враховує нульових значень, і IF/ CASEповертає null, коли умова не виконується і немаєELSE .

Я думаю, що це краще, ніж використовувати SUM().


1

Не специфічно для продукту, але стандарт SQL передбачає

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

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

І звичайно продавці вважають за краще дотримуватися своїх фірмових рішень.


1
Я ніколи раніше про це не чув, тому подивився. За даними modern-sql.com/feature/filter, єдина основна СУБД, яка фактично пропонує FILTERпропозицію, - це PostgreSQL, але вона імітується CASEусіма ними.
Крістен Хаммак

1

Чому б не так?

SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1

1
Тому що йому потрібно набагато більше, ніж просто підрахунок. Він намагається отримати кількість членів групи, а потім сукупність цілої групи, чого не можна зробити з WHERE.
Крістен Хаммак

1

Мені довелося використовувати COUNTIF () у моєму випадку як частину моїх колон SELECT AND, щоб імітувати% від кількості разів, коли кожен елемент з’являвся у моїх результатах.

Тому я використав це ...

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

Звичайно, вам потрібно буде відформатувати результат у відповідності з вашими вимогами до дисплея.


-2
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.