avg()必须配合group by才能计算每组平均值;单独使用只返回全表平均值,漏写group by会导致报错或结果错误,非聚合字段须全部出现在group by中,null值自动忽略,where用于分组前过滤,having用于分组后筛选。

AVG() 必须配合 GROUP BY 才能算每组平均值
单独写 SELECT AVG(salary) FROM employees 只会返回整个表的全局平均值,不是“每组”。要按部门、岗位、年份等维度分组计算,GROUP BY 是硬性前提,缺它就得不到分组结果。
常见错误是漏写 GROUP BY 却在 SELECT 里混用非聚合字段,比如:SELECT dept, AVG(salary) FROM employees —— 大多数数据库(如 PostgreSQL、MySQL 严格模式)直接报错 column "dept" must appear in the GROUP BY clause。
- 正确写法必须显式列出所有非聚合字段:
SELECT dept, AVG(salary) FROM employees GROUP BY dept - MySQL 旧版本可能允许不写
GROUP BY,但结果不可靠(随机取某行的dept值),别依赖 - 如果还要筛选分组后的平均值,必须用
HAVING,不是WHERE:例如HAVING AVG(salary) > 5000
NULL 值会被 AVG() 自动忽略,但空字符串或 0 不算 NULL
AVG() 只统计非 NULL 的数值行。如果某组里 salary 有三行:8000、NULL、6000,结果是 (8000 + 6000) / 2 = 7000,不是 / 3。
容易踩坑的是把缺失数据存成 0 或空字符串 '' —— 这些都不是 NULL,会被计入分母和分子,拉低平均值。比如误把离职员工薪资记为 0,会导致部门平均工资严重失真。
- 检查数据质量:
SELECT COUNT(*), COUNT(salary), COUNT(NULLIF(salary, 0)) FROM employees WHERE dept = 'tech' - 需要排除 0 值时,用条件聚合:
AVG(CASE WHEN salary > 0 THEN salary END) - 确认字段是否允许
NULL:DESCRIBE employees或查information_schema.columns
AVG 返回 DECIMAL 或 FLOAT,精度可能出乎意料
不同数据库对 AVG() 的返回类型处理不一致:PostgreSQL 默认返回 numeric(高精度),MySQL 返回 DOUBLE,SQL Server 返回与输入类型匹配的近似数值类型。这意味着 AVG(age)(整型)可能返回带多位小数的结果,比如 32.666666666666664。
如果业务要求保留两位小数,不能只靠应用层四舍五入 —— 数据库层截断更可控,且避免浮点误差累积。
- 通用做法:
ROUND(AVG(salary), 2) - PostgreSQL 可强转:
AVG(salary)::DECIMAL(10,2) - 注意:SQLite 的
AVG()对整数输入也返回浮点数,无法直接控制小数位,得套ROUND()
性能提示:GROUP BY + AVG 在大数据量下容易慢
没有索引时,GROUP BY dept 需要全表扫描+哈希分组或排序,当 employees 表超千万行,响应可能从毫秒级升到秒级。
优化核心是让数据库快速定位和分组,而不是靠计算加速。
- 在
GROUP BY字段上建索引:CREATE INDEX idx_dept ON employees(dept) - 如果只查特定部门,加
WHERE dept IN ('sales', 'tech')能大幅减少输入行数 - 避免在
GROUP BY字段上用函数,比如GROUP BY UPPER(dept)会让索引失效
分组平均值本身计算很快,瓶颈永远在数据读取和分组过程 —— 索引和过滤条件比调优 AVG() 函数更重要。











