GROUP BY是分组计算的硬性要求,缺失会导致报错或结果错乱;WHERE过滤分组前数据,HAVING过滤分组后聚合结果;AVG()忽略NULL但不处理空字符串或非法文本;需用窗口函数实现每行显示组内均值。

漏写GROUP BY会导致报错或结果错乱
单独用 AVG() 只能算整张表的平均值;想按部门、班级、年份等维度分组计算,GROUP BY 不是可选项,是硬性要求。MySQL 8.0+ 严格模式下会直接报 ERROR 1055,PostgreSQL 和 SQL Server 则拒绝执行。
常见错误写法:SELECT name, AVG(score) FROM students; —— name 既不是聚合字段,也没出现在 GROUP BY 中,语法非法。
- 正确写法必须显式声明分组依据:
SELECT department, AVG(salary) FROM employees GROUP BY department; - 多个分组字段用逗号隔开:
GROUP BY year, region -
SELECT列表里所有非聚合字段(如department、class)都得完整出现在GROUP BY子句中
WHERE 和 HAVING 的分工不能颠倒
WHERE 在分组前过滤原始行,HAVING 在分组后过滤聚合结果。想查“平均分高于 85 的班级”,必须用 HAVING,而不是把 AVG() 塞进 WHERE。
错误示例:SELECT class, AVG(score) FROM exams WHERE AVG(score) > 85 GROUP BY class; → 直接语法错误,因为 WHERE 阶段 AVG() 还没计算。
- 正确写法:
SELECT class, AVG(score) FROM exams GROUP BY class HAVING AVG(score) > 85; - 组合使用时顺序固定:先
WHERE筛原始数据(如WHERE subject = 'math'),再分组,最后HAVING筛组 - 如果只对某类数据求平均(比如只算数学成绩),用
WHERE就够了,不必上GROUP BY
NULL 值自动忽略,但空字符串和非法文本不等于 NULL
AVG() 确实跳过 NULL,但不会跳过 ''、'abc' 或 '0'。这些值在不同数据库中行为差异很大:PostgreSQL 直接报错,MySQL 可能隐式转成 0,把平均值拉低。
- 先检查数据质量:
SELECT COUNT(*), COUNT(score), COUNT(NULLIF(score, '')) FROM results; - 稳妥过滤写法:
AVG(CASE WHEN score > 0 THEN score END) - 别用
COALESCE(score, 0)补值——这会让缺失数据以 0 参与计算,结果失真 - 类型不匹配时,优先显式转换:
AVG(CAST(score AS DECIMAL(10,2)))
想保留原始行数?改用窗口函数 AVG() OVER (PARTITION BY ...)
如果目标是“每行显示它所在组的平均值”,而不是“压缩成一行汇总”,GROUP BY 就不合适——它会丢掉明细。这时候该用窗口函数。
错误写法:AVG(score) OVER (ORDER BY id) → 没 PARTITION BY,变成全局累计平均;漏 ORDER BY 又会退化成静态组内均值。
- 正确结构:
AVG(score) OVER (PARTITION BY class_id)(静态组均值) - 移动平均需加
ORDER BY和ROWS:AVG(score) OVER (PARTITION BY class_id ORDER BY exam_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) - 注意排序列要有确定性:时间戳重复时,补主键避免结果不稳定,例如
ORDER BY exam_date, id - 窗口函数不能直接用于
WHERE,要用子查询或 CTE 包一层
AVG() 不报错不代表结果可信,尤其是从 Excel 或日志导入的数据,表面是数字,实则混着空格、单位符号或空字符串。动手前先跑两行检查语句,比调半天逻辑更省时间。

















