相当于COUNTIF聚合函数的SQL Server


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而失败,但是这里的想法是确定MyColumn的所有值为'1'的行的百分比。

关于如何在MS SQL 2005环境中正确实现这一点的任何想法?

Answers:


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
(我知道OP询问MS SQL,只是SQLite的用户做同样的事情一个小评论)的SQLite没有ISNULL,而是你可以做CASE WHEN myColumn IS NULL,或使用ifnullstackoverflow.com/a/799406/1861346
马特

54

我通常会按照Josh的建议去做,但是集思广益并测试了我觉得很喜欢分享的稍微曲折的选择。

您可以利用COUNT(ColumnName)不计算NULL的事实,并使用如下代码:

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

NULLIF-如果两个传入的值相同,则返回NULL。

优点:将您的意图表达为COUNT行,而不是SUM()表示法。缺点:不清楚其工作方式(“魔术”通常很糟糕)。


2
这个解决方案可以给出比之和的不同的答案时的基团只包含空值它产生1而不是0
KimvdLinde

旧帖子,但是谢谢您的帮助。我扩展了魔术,并通过添加ISNULL如下内容解决了“仅空值”问题:SELECT COUNT(NULLIF(0, ISNULL(myColumn, 0)))。等等,这看起来很丑...
pcdev

1
如果有NULLIFNOT函数,那就完美了
qwertzguy,

21

我会使用这种语法。它的实现与Josh和Chris的建议相同,但它的优点是符合ANSI,并且不受特定数据库供应商的束缚。

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

2
克里斯的答案是符合Stndard SQL的要求(提示:NULLIF包括在Standard SQL-92中)。替换为isnull,可以轻松将Josh的答案转换为Standard SQL COALESCE
2011年

我实际上最喜欢这个答案,因为它具有Chris所展示的“计数行”的思想,但由于您可以使用任何比较运算符,因此它具有更大的可扩展性。不只是=。我将其用于“计算响应数> = 2”。
克里斯汀·哈马克

3

加上乔希的答案,

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

2

怎么样

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

CASE:) 短

之所以有效,COUNT()是因为它不计算null值,并且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子句的唯一主要DBMS 是PostgreSQL,但CASE在所有这些子句中都对其进行了仿真。
克里斯汀·哈马克

1

为什么不这样呢?

SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1

1
因为他需要的不仅仅是计数。他正在尝试获取组中一部分的行数,然后是整个组的汇总,而WHERE是您无法做到的。
克里斯汀·哈马克

1

在我的情况下,我必须使用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

当然,您将需要根据显示要求格式化结果。


-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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.