漏掉 GROUP BY 就不是分组,只是查总数;真正分组必须显式加 GROUP BY department,否则数据库无法按维度切块统计,常见错误包括误用 WHERE 替代分组、HAVING 中滥用字段、非聚合字段未入 GROUP BY 或未聚合。

漏掉 GROUP BY 就不是分组,只是查总数
很多人写 SELECT COUNT(*) FROM emp WHERE name LIKE '%经理%',以为在按部门统计含“经理”的人数,结果只返回一个数字。这不是分组,是全表过滤后计数。真正分组必须显式加 GROUP BY department,否则数据库根本不知道你打算按什么切块。
常见错误场景:
- 想看每个部门里“总监”“主管”各有多少人,却分别写两个带
WHERE的SELECT再拼接——逻辑错、性能差、NULL 组易丢 - 把
LIKE条件写进HAVING,比如HAVING name LIKE '%admin%'——HAVING是对已分组结果做整组筛选,不是逐行判断,字段值在GROUP BY后已不可直接引用 - SELECT 列表里出现非聚合字段(如
department)但没放进GROUP BY,MySQL 5.7+ 严格模式会报错,低版本可能返回不可靠结果
CASE WHEN + COUNT 或 SUM 才能并列统计多个条件
WHERE 只能保留/排除整行,无法让“男性数”“女性数”“未填数”共存于同一行输出。必须用 CASE WHEN 在每行打标记,再聚合。
推荐写法(兼容性好、不易错):
SELECT region, SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) AS active_cnt, SUM(CASE WHEN status = 'inactive' THEN 1 ELSE 0 END) AS inactive_cnt FROM users GROUP BY region;
注意点:
-
COUNT(CASE WHEN ... THEN 1 END)依赖隐式ELSE NULL,安全;但若误写ELSE 0,COUNT会把 0 当有效值计入,结果虚高 -
SUM(CASE ...)语义更直白,MySQL 5.7 及更早版本对COUNT嵌套CASE支持偏弱,统一用SUM更稳 - 所有
CASE必须放在同一SELECT中,不能在GROUP BY里引用别名(如GROUP BY active_cnt是非法的)
LIKE 匹配大小写行为不统一,别靠默认
MySQL 默认不区分大小写,PostgreSQL 和 SQL Server 默认区分,SQLite 看编译选项。写 name LIKE '%Admin%' 在 PostgreSQL 里可能查不到 'admin',但在 MySQL 里能命中。
显式控制才可靠:
- MySQL:用
COLLATE utf8mb4_bin强制区分,如name COLLATE utf8mb4_bin LIKE '%Admin%' - PostgreSQL:用
ILIKE实现不区分大小写,如name ILIKE '%admin%' - 通用写法:
LOWER(name) LIKE LOWER('%admin%'),但注意该写法通常无法走索引
另外,LIKE 左边带通配符(如 '%张%')基本无法利用前缀索引;只有 '张%' 这种左匹配才可能走索引。
字段为 NULL 时 LIKE 结果也是 NULL,COUNT 自动忽略
如果 name 允许为 NULL,那么 name LIKE '%x%' 对应行的表达式结果就是 NULL,而 COUNT() 天然跳过 NULL,不会被计入——这点常被忽略,导致统计数比预期少。
验证方式:
- 先查
SELECT COUNT(*) FROM emp WHERE name IS NULL,确认空值比例 - 再对比
COUNT(CASE WHEN name LIKE '%x%' THEN 1 END)和SUM(CASE WHEN name IS NOT NULL AND name LIKE '%x%' THEN 1 ELSE 0 END)的差异 - 若业务上需把
NULL视为“不含目标字符”,当前写法没问题;若需单独统计NULL行,则得额外加一列,如COUNT(CASE WHEN name IS NULL THEN 1 END)
最易被绕过的细节是:你以为在统计“含某字符的记录数”,其实连 NULL 都没算进去,而业务方可能默认它该归入“未匹配”类。

















