count(*)配合where只能返回全表匹配行的总数,无法实现按部门等维度分组统计;正确做法是用group by分组后,再结合sum(case when name like '%admin%' then 1 else 0 end)逐行判别并累加。

统计含特定字符的行数,为什么不能只用 WHERE + COUNT(*)
直接写 COUNT(*) 配合 WHERE name LIKE '%admin%' 只会返回一个总数,不是按分组统计的结果。比如你想看每个部门里含“主管”的人数,漏掉 GROUP BY department,结果就只剩一行数字,跟部门完全无关。
更关键的是:这种写法必须扫描全表两次才能算出两个条件(比如同时要“含总监”和“含主管”),而用 SUM(CASE WHEN ...) 只扫一次。
- WHERE 是在聚合前过滤整行,会丢掉其他分组所需数据
- HAVING 是在 GROUP BY 后筛组,不能用于单行条件判断
- 真正需要的是“每行先判一次,再加总”,也就是把逻辑塞进聚合函数内部
用 SUM(CASE WHEN name LIKE ...) 时必须写 ELSE 0
SUM(CASE WHEN name LIKE '%error%' THEN 1 END) 看似简洁,但没写 ELSE 0 会导致未匹配行贡献 NULL;而 SUM() 遇到全 NULL 会返回 NULL,不是 0 —— 这在报表或下游计算中容易引发空值传播问题。
正确写法是显式兜底:
SUM(CASE WHEN name LIKE '%error%' THEN 1 ELSE 0 END) AS error_cnt
- 字段本身为
NULL时,name LIKE '%x%'结果也是NULL,不会进THEN分支,靠ELSE 0保底 - 别用
COALESCE(SUM(...), 0)补救——这是掩盖问题,不是解决问题 - MySQL、PostgreSQL、SQL Server、Oracle 全部支持该写法,兼容性无风险
多个 LIKE 条件并列写,别嵌套
要同时统计“含‘运维’”“含‘开发’”“含‘测试’”的记录数,常见错误是写成嵌套 CASE:
SUM(CASE WHEN name LIKE '%运维%' THEN 1 ELSE CASE WHEN name LIKE '%开发%' THEN 1 ELSE 0 END END)
这不仅难读,还会让优化器难以并行处理。正确方式是三个独立 SUM:
SUM(CASE WHEN name LIKE '%运维%' THEN 1 ELSE 0 END) AS ops_cnt,<br>SUM(CASE WHEN name LIKE '%开发%' THEN 1 ELSE 0 END) AS dev_cnt,<br>SUM(CASE WHEN name LIKE '%测试%' THEN 1 ELSE 0 END) AS test_cnt
- 每个
SUM独立计算,互不影响 - 同一行可能同时命中多个条件(比如“运维开发岗”),各计数都会 +1,符合业务预期
- Oracle 中若需大小写敏感匹配,改用
INSTR(name, '运维') > 0更稳妥(LIKE在 Oracle 默认区分大小写)
LIKE 匹配性能与大小写陷阱
LIKE '%xxx%' 无法走索引,纯靠全表扫描;如果字段允许为空,name LIKE '%x%' 对 NULL 值永远返回 NULL,不进 THEN 分支——这点常被忽略。
大小写行为因数据库而异:
- MySQL 默认不区分大小写,
name LIKE '%Admin%'能匹配'admin' - PostgreSQL 和 SQL Server 默认区分,得用
ILIKE或COLLATE显式控制 - 通用写法是
LOWER(name) LIKE LOWER('%admin%'),但注意它必然放弃索引
真正容易被忽略的点是:当你把 LIKE 放进 CASE WHEN,它就不再是“过滤谓词”,而是“每行求值表达式”——这意味着 NULL 字段、空字符串、前后空格都会影响结果,上线前务必用真实数据验证边界 case。










