必须将非分组列加入group by或用聚合函数处理,否则数据库因无法确定组内多值字段取值而报错;mysql 5.7+、postgresql、oracle等严格拒绝执行,旧版mysql静默返回不可靠结果。

SELECT里写了非分组列又没套聚合函数
这是最常被喷的错误。比如写 SELECT dept_id, name, AVG(salary) FROM emp GROUP BY dept_id,数据库直接报错 Error 1055(MySQL)或 ORA-00979(Oracle)。原因很简单:dept_id 分组后,一个部门对应多个 name,SQL 不知道该挑张三还是李四。
- 严格模式下(MySQL 5.7+、PostgreSQL、Oracle),直接拒绝执行
- 旧版 MySQL(5.6 或关闭
ONLY_FULL_GROUP_BY)会静默返回某一行的name,但结果不可靠、不可复现 - 别指望“它以前能跑”,迁移或换数据库就崩
用 ANY_VALUE() 就以为万事大吉
ANY_VALUE(name) 确实能绕过报错,但它不解决语义问题——它只是明确告诉数据库:“我就要随机挑一个,别拦我”。这在统计报表里可能没问题,但在业务关键路径上很危险:
- 同一查询多次执行,
ANY_VALUE(name)可能返回不同值(尤其涉及并发写入或优化器重排) - 如果
name实际和dept_id存在函数依赖(比如每个部门只配一个负责人),应显式建约束或用MAX(name)+ 注释说明逻辑,而非依赖ANY_VALUE - PostgreSQL 和 Oracle 根本不支持
ANY_VALUE,代码一换库就失效
GROUP BY 里写 SELECT 中的别名
写成 SELECT user_id AS uid, COUNT(*) FROM logs GROUP BY uid 是错的。SQL 执行顺序是 FROM → WHERE → GROUP BY → HAVING → SELECT,GROUP BY 阶段根本还没看到 uid 这个别名。
- 必须写成
GROUP BY user_id,哪怕字段名很长也得原样写 - 别名只能在
ORDER BY和HAVING(部分数据库)中安全使用 - 某些 ORM 自动生成 SQL 时会犯这个错,要检查生成语句,不能无脑信
WHERE 里用了聚合函数还纳闷为啥报错
SELECT dept_id, AVG(salary) FROM emp WHERE AVG(salary) > 5000 GROUP BY dept_id 必然失败。因为 WHERE 在分组前执行,此时 AVG(salary) 还没算出来。
- 过滤聚合结果必须用
HAVING:把WHERE换成HAVING AVG(salary) > 5000 -
HAVING只能用在含GROUP BY的查询中;没有分组却想按聚合过滤?先加GROUP BY,哪怕只分一组(如GROUP BY 1) - 别混淆:WHERE 过滤行,HAVING 过滤组
name 和 dept_id 之间没业务约束,ANY_VALUE 或子查询返回的结果,本质上仍是未定义行为。











