应使用两个 SUM(CASE WHEN ... THEN 1 ELSE 0 END) 分别统计满足与不满足条件的行数,而非 COUNT(CASE WHEN) 加 COUNT(*) 减法,因后者会漏计 NULL 行且无法区分 false 与 unknown;显式覆盖 NULL 分支(如 status IS NULL)确保语义准确、结果可靠。

直接用 SUM(CASE WHEN) 统计满足/不满足条件的两组数量
要同时拿到“满足条件”和“不满足条件”的行数,最稳的方式是写两个 SUM(CASE WHEN ... THEN 1 ELSE 0 END):一个统计真值,一个统计假值。别用 COUNT(CASE WHEN ... THEN 1 END) 去算满足数,再用 COUNT(*) - 上面结果 算不满足——这在有 NULL 或分组时容易错漏。
-
SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END)→ 满足条件的计数(含显式 0) -
SUM(CASE WHEN status != 'paid' OR status IS NULL THEN 1 ELSE 0 END)→ 不满足条件的计数(必须覆盖 NULL) - 如果字段定义为
NOT NULL,可简化为SUM(CASE WHEN status != 'paid' THEN 1 ELSE 0 END) - 避免写成
COUNT(CASE WHEN status = 'paid' THEN 1 END)+COUNT(*) - ...:当该字段本身含 NULL 时,COUNT(*)包含 NULL 行,但COUNT(CASE...)不包含,差值就不等于“不满足”
为什么不能只靠 COUNT(CASE WHEN) + COUNT(*) 推导
表面看 COUNT(*) 减去 COUNT(CASE WHEN cond THEN 1 END) 像能得出“不满足”数,但实际会漏掉 NULL 行,且无法区分“明确为 false”和“未知(NULL)”。
- 假设
status列有值'paid'、'pending'和NULL,那么COUNT(CASE WHEN status = 'paid' THEN 1 END)只计 paid 行;COUNT(*)计全部三类;差值 = pending + NULL 行数,但你无法知道其中多少是 NULL - 业务上常需分开统计:
unpaid_count(明确 != paid)、unknown_status_count(NULL),这时必须显式写分支 - 若强行用减法,后续做百分比时分母错位(比如除以
COUNT(*)却把 NULL 当作 “不满足”,语义就歪了)
分组场景下统计每组的满足/不满足比例
在 GROUP BY 后算每组内满足与不满足的占比,推荐用 AVG(CASE WHEN ... THEN 1.0 ELSE 0 END),它天然规避除零、自动忽略 NULL(只要你写了 ELSE 0),比手写除法更安全。
-
AVG(CASE WHEN score >= 60 THEN 1.0 ELSE 0 END)→ 直接返回该组及格率(小数) - 等价于
SUM(CASE WHEN score >= 60 THEN 1 ELSE 0 END) * 1.0 / COUNT(*),但不用处理COUNT(*) = 0的报错 - 如果想保留整数百分比,套一层
ROUND(... * 100, 0)即可 - 注意:MySQL/SQL Server 需显式写
1.0,PostgreSQL 支持AVG(score >= 60)(bool 自转 float)
跨数据库兼容写法的关键细节
所有主流数据库都支持 SUM(CASE WHEN ... THEN 1 ELSE 0 END),但日期、字符串、NULL 的处理细节极易踩坑。
- 日期年份提取:
YEAR(order_date)(MySQL/SQL Server)、EXTRACT(YEAR FROM order_date)(PostgreSQL)、strftime('%Y', order_date)(SQLite) - 字符串比较:用单引号
'active',别用双引号(PostgreSQL 中双引号是标识符) - NULL 安全判断:写
status IS NULL或status 'paid'(MySQL 空值安全等于),别依赖=或!= - 性能提示:多个条件并列统计时,
SUM(CASE ...)只扫一遍表;拆成多个WHERE子查询会反复扫描,大数据量下明显变慢
实际用的时候,最常被忽略的是 NULL 分支是否显式覆盖——它不报错,但结果静默偏移。写完先用 SELECT COUNT(*) FILTER (WHERE col IS NULL)(PostgreSQL)或 AVG(CASE WHEN col IS NULL THEN 1.0 ELSE 0 END) 查查 NULL 比例,再决定 CASE 里要不要加这一支。

















