GROUP BY 多字段必须用逗号分隔,不可加括号或AND;开启ONLY_FULL_GROUP_BY时SELECT非聚合字段须全部列在GROUP BY中;取每组首行应使用ROW_NUMBER()窗口函数而非GROUP BY;联合分组性能依赖与GROUP BY顺序一致的覆盖索引;HAVING用于分组后过滤,WHERE用于分组前过滤。

GROUP BY 多字段写法必须用逗号分隔,括号是语法错误
直接写 GROUP BY col1, col2, col3 就行,别加括号——GROUP BY (col1, col2) 在 MySQL 8.0+ 会报 syntax error near '(';GROUP BY col1 AND col2 则会被当成布尔表达式,结果完全不对。
常见错误现象:执行时报错 ERROR 1055 (42000): Expression #3 of SELECT list is not in GROUP BY clause,本质是开启了 ONLY_FULL_GROUP_BY 模式,而你 SELECT 里写了没聚合也没列在 GROUP BY 中的字段。
- 正确写法:
SELECT dept_id, job_title, COUNT(*) FROM employees GROUP BY dept_id, job_title - 如果用了
SELECT *,所有非聚合字段(比如name、hire_date)都得手动列进GROUP BY,否则必报错 - 字段顺序不影响分组逻辑,但会影响默认排序(尤其 MySQL 5.7 及以前),建议和
SELECT顺序保持一致
想取每组第一条原始记录?别用 GROUP BY,改用 ROW_NUMBER()
GROUP BY 本身只能输出聚合结果(如 COUNT、MAX),拿不到原始行。比如“每个部门+职级薪资最高的人”,GROUP BY dept_id, job_title 配 MAX(salary) 只能返回数值,无法带回 emp_id 或 name。
必须用窗口函数,且优先选 ROW_NUMBER():
SELECT emp_id, dept_id, job_title, salary
FROM (
SELECT emp_id, dept_id, job_title, salary,
ROW_NUMBER() OVER (PARTITION BY dept_id, job_title ORDER BY salary DESC) AS rn
FROM employees
) t
WHERE rn = 1;
-
PARTITION BY dept_id, job_title对应联合分组逻辑 -
ORDER BY salary DESC定义“第一条”的含义;换成hire_date DESC就是最新入职者 - 别误用
RANK()或DENSE_RANK()——遇到并列薪资时可能返回多行,破坏“每组一条”预期
多字段分组性能差?大概率是索引没对上
联合分组本身不慢,慢在全表扫描后内存排序分组。关键看有没有覆盖索引支撑 GROUP BY 字段 + SELECT 中的非聚合字段。
例如查询 SELECT city, industry, COUNT(*) FROM companies GROUP BY city, industry,理想索引是:
CREATE INDEX idx_city_industry ON companies(city, industry);
- 索引字段顺序必须和
GROUP BY顺序一致(MySQL 强制要求最左前缀匹配) - 如果查询还带
WHERE status = 'active',要把status放索引最前面:(status, city, industry) - 避免在分组字段上用函数,比如
GROUP BY UPPER(city)会让索引失效
HAVING 过滤组合频次,不是 WHERE
WHERE 在分组前过滤单行,HAVING 在分组后过滤“组合组”。想筛出高频组合(比如出现 ≥5 次的城市-行业对),必须用 HAVING:
SELECT city, industry, COUNT(*) AS cnt FROM companies GROUP BY city, industry HAVING COUNT(*) >= 5;
-
HAVING COUNT(*) >= 5是标准写法;部分数据库(如 PostgreSQL)不支持用别名HAVING cnt >= 5,别偷懒 - 别在
HAVING里引用未出现在GROUP BY或SELECT中的字段,比如HAVING name = 'Alice'会直接报错 - 如果组合本身不存在(比如某城市没对应任何行业),
GROUP BY不会生成该行;要补全得用CROSS JOIN+LEFT JOIN,不是HAVING能解决的
GROUP BY,后者必须绕开它。另外,索引字段顺序和 GROUP BY 顺序不一致时,MySQL 基本等于没索引。

















