group by 必须包含所有非聚合字段,否则mysql 5.7+或postgresql报错error 1055;where过滤行、having过滤分组结果;多字段分组注意null处理与索引覆盖;count(*)、count(col)、sum(col)语义不同,需按需选用。

GROUP BY 必须包含所有非聚合字段
写 GROUP BY 时如果 SELECT 里有普通字段(非 COUNT/SUM 等),这些字段必须出现在 GROUP BY 子句中,否则 MySQL 5.7+ 或 PostgreSQL 会报错:ERROR 1055。这不是“语法建议”,是严格校验。
- ✅ 正确:
SELECT department, COUNT(*) FROM employees GROUP BY department - ❌ 错误:
SELECT department, name, COUNT(*) FROM employees GROUP BY department(name未分组,且无聚合) - ⚠️ 注意:MySQL 5.7 之前默认允许“隐式分组”,但结果不可靠——
name取的是该组任意一行的值,不是最常见/第一个/最小值
WHERE 和 HAVING 的分工不能混
WHERE 过滤行,HAVING 过滤分组后的结果。想筛“订单数超过 5 的用户”,必须用 HAVING COUNT(*) > 5;若写成 WHERE COUNT(*) > 5,直接报错:Invalid use of group function。
-
WHERE在分组前执行,只能用原始列(如status = 'paid') -
HAVING在分组后执行,可引用聚合函数和GROUP BY字段 - 性能上,优先用
WHERE缩小数据集,再分组,避免对百万行全量聚合
多字段分组要注意顺序和 NULL 处理
按 GROUP BY region, category 和 GROUP BY category, region 逻辑等价,但排序结果不同;更关键的是,NULL 在分组中被视为一个独立值——两行 region = NULL 会被归入同一组,但不会和任何非 NULL 值匹配。
- 若业务上想把
NULL当作“未知”单独统计,无需额外处理;但若想合并进某类(如“Other”),得先COALESCE(region, 'Other') - 复合分组时,索引要覆盖全部分组字段才高效,例如
INDEX (region, category)能加速GROUP BY region, category,但INDEX (category, region)效果差 - 别在分组字段上用函数,比如
GROUP BY YEAR(order_date)会导致索引失效
聚合函数选错会导致语义错误
COUNT(*)、COUNT(col)、COALESCE(SUM(col), 0) 行为差异很大,不注意会统计出错。
-
COUNT(*)统计行数(含NULL);COUNT(sales)只统计sales IS NOT NULL的行 -
SUM(sales)遇到整列全NULL返回NULL,不是0;需要补零就写COALESCE(SUM(sales), 0) -
AVG()自动忽略NULL,但分母是有效值个数,不是总行数——这点常被误读 - 想取每组最新一条记录的某个字段?
MAX(created_at)可行,但MAX(name)是字典序最大,不是“最新那条的 name”
HAVING 条件也没用。










