sum(case when)比count(case when)更可靠,因其语义明确、行为可控:count仅统计非null值,若case中误写else 0会导致所有不匹配行被计数;而sum(case when...then 1 else 0 end)始终显式控制每行贡献0或1,避免计数翻倍或归零。

直接用 CASE WHEN 配合 SUM(),别用 COUNT(CASE WHEN) —— 后者容易因 ELSE 处理不当导致计数翻倍或归零。
为什么 SUM(CASE WHEN) 比 COUNT(CASE WHEN) 更可靠
COUNT() 只统计非 NULL 值,而 CASE WHEN 不匹配时默认返回 NULL;但一旦你写了 ELSE 0,所有不满足条件的行都会被计入,结果就变成“总行数”,不是你想要的“该状态数量”。SUM(CASE WHEN ... THEN 1 ELSE 0 END) 语义清晰、行为确定,不会误判。
-
COUNT(CASE WHEN status = 'done' THEN 1 END)✅ 安全(不匹配 →NULL→ 不计) -
COUNT(CASE WHEN status = 'done' THEN 1 ELSE 0 END)❌ 错误(不匹配 →0→ 被计为 1 次) -
SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END)✅ 推荐(显式控制,无歧义)
统计多个状态且带总数:一行写完
要同时拿到总记录数、各状态数量,用 SUM() 并列计算最稳。例如统计订单表中 status 为 'paid'、'shipped'、'cancelled' 的数量,再加总数:
SELECT COUNT(*) AS total_count, SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) AS paid_count, SUM(CASE WHEN status = 'shipped' THEN 1 ELSE 0 END) AS shipped_count, SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) AS cancelled_count FROM orders;
注意:COUNT(*) 是真总数(含 NULL 状态),而各 SUM 只算明确匹配的值;如果 status 允许 NULL 或非法值,它们不会被任何 SUM 统计进去——这是预期行为,不是 bug。
GROUP BY 项目+状态时漏数据?检查分组字段是否齐全
想按项目分别看各状态任务数,必须同时 GROUP BY project_id, status。只写 GROUP BY status 会把所有项目混在一起;只写 GROUP BY project_id 则压根得不到状态分布。
- 缺失某状态(如某项目没有
'cancelled'记录)→ 结果里根本不会出现这行,这是 SQL 标准行为 - 需要强制补 0?得用
LEFT JOIN状态字典表,不是加个COALESCE就能解决 -
status字段含空格或大小写不一致(如'Done'和'done')→ 会被当两个不同值,先清洗再统计
大表上跑多状态聚合,索引怎么建
如果 WHERE 条件固定(比如只查 del_flag = 0 的记录),且常按 status 分类统计,建议建复合索引:
-
INDEX (del_flag, status)—— 覆盖过滤+分组,避免回表 - 若还常
GROUP BY project_id, status,优先建INDEX (del_flag, project_id, status) - 别单独给
status建单列索引:选择率低,优化器大概率不走
真正容易被忽略的是:状态字段若有大量 NULL 或非法值(如 'unknown'、''),它们会参与分组但语义模糊,最好在 CASE 中统一映射,而不是依赖应用层补救。










