group by必须配合聚合函数使用,且select中非聚合字段必须出现在group by子句中,否则mysql 5.7+等严格模式下报error 1055;where用于分组前过滤行,having用于分组后过滤组,null值在group by中被归为同一组。

GROUP BY 不能单独使用,必须配合聚合函数(如 COUNT()、SUM()、AVG())才有意义,否则会报错或返回不可预期结果。
GROUP BY 后字段必须出现在 SELECT 列表中(或被聚合)
很多初学者写 SELECT name, COUNT(*) FROM users GROUP BY age 会报错——因为 name 既没参与分组,也没被聚合。SQL 标准要求:SELECT 中每个非聚合字段,都必须明确出现在 GROUP BY 子句里。
- ✅ 正确:
SELECT age, COUNT(*) FROM users GROUP BY age - ✅ 正确:
SELECT department, AVG(salary) FROM employees GROUP BY department - ❌ 错误:
SELECT name, department, COUNT(*) FROM employees GROUP BY department(name未分组也未聚合) - ⚠️ 注意:MySQL 5.7+ 默认启用
ONLY_FULL_GROUP_BY模式,会严格校验;旧版或关闭该模式时可能“侥幸通过”,但结果无意义(name取的是组内某一行的随机值)
WHERE 和 HAVING 的分工容易混淆
WHERE 过滤行,HAVING 过滤组——这是最关键的语义区别。很多人把条件写错位置,导致逻辑错误或语法报错。
- 过滤原始数据用
WHERE:SELECT city, COUNT(*) FROM users WHERE status = 'active' GROUP BY city - 过滤分组后结果用
HAVING:SELECT city, COUNT(*) FROM users GROUP BY city HAVING COUNT(*) > 100 - ❌ 错误:
HAVING status = 'active'(status是行级字段,不是聚合结果,不能在 HAVING 中直接用) - ⚠️ 性能提示:WHERE 越早过滤,GROUP BY 处理的数据越少;HAVING 是在分组完成后才执行,无法利用索引加速
NULL 值在 GROUP BY 中会被归为同一组
如果分组字段含 NULL,所有 NULL 值会被视为“相等”并合并成一个组——这点常被忽略,导致统计偏差。
- 示例:
SELECT category, COUNT(*) FROM products GROUP BY category,若 5 条记录category为NULL,结果会出现一行NULL | 5 - 想排除空值?加
WHERE category IS NOT NULL - 想单独标记空值组?可配合
CASE WHEN:SELECT CASE WHEN category IS NULL THEN 'Uncategorized' ELSE category END AS grp, COUNT(*) FROM products GROUP BY grp - ⚠️ 注意:不同数据库对
NULL排序顺序略有差异,但分组行为一致
真正麻烦的不是语法,而是理解「分组」本质:它把多行压缩成一行,而每行输出必须能唯一代表该组。一旦 SELECT 列表里混入未聚合的细节字段,就违背了这个前提——这时候报错反而是好事。











