直接使用avg()配合group by即可统计分组平均值,无需子查询;avg()自动忽略null值、要求非数值字段须在group by中出现,搭配count()和min()/max()可识别异常值。

GROUP BY后直接用AVG()函数就行
SQL里统计分组平均值不需要额外子查询或临时表,AVG() 是聚合函数,天然支持配合 GROUP BY 使用。只要确保目标字段是数值类型(比如 INT、FLOAT),它会自动对每组内非 NULL 值计算算术平均。
常见错误是把 AVG() 写在 WHERE 子句里,或者误以为要先 SELECT 出所有行再手动求均值——这两者都语法报错或逻辑错误。
-
AVG()会忽略NULL值,但不会跳过整行:只要该字段为NULL,就不参与该组的平均计算 - 如果某组所有对应值全为
NULL,AVG()返回NULL,不是 0 - 想保留小数位数?直接在
AVG()外套ROUND(AVG(col), 2),别用CAST强转类型来“取整”
注意字段是否在GROUP BY中出现
MySQL 5.7+ 和 PostgreSQL、SQL Server 等严格模式下,SELECT 列表里除了聚合函数(如 AVG()、COUNT()),其余字段必须出现在 GROUP BY 子句中。否则会报错:ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause。
例如:SELECT dept, AVG(salary) FROM emp GROUP BY dept 合法;但 SELECT dept, name, AVG(salary) FROM emp GROUP BY dept 就非法——因为 name 没参与分组,数据库不知道该取哪一行的 name。
- 若真需要展示某组代表性的非聚合字段(比如组内最高薪员工姓名),得用窗口函数或子查询,不能靠简单
GROUP BY - MySQL 5.7 之前默认允许“宽松模式”,但开启
sql_mode=ONLY_FULL_GROUP_BY后行为一致,建议始终按严格规则写
AVG()和COUNT()一起用能发现数据偏差
光看平均值容易被异常值带偏。比如某部门平均薪资 15k,但实际是 1 人 80k + 9 人 5k —— 这种分布下,AVG() 隐藏了离散性。搭配 COUNT() 和 MIN()/MAX() 一起查,更可靠。
SELECT dept, AVG(salary) AS avg_salary, COUNT(*) AS emp_count, MIN(salary) AS min_salary, MAX(salary) AS max_salary FROM emp GROUP BY dept;
-
COUNT(*)统计每组总行数,COUNT(salary)只统计非NULL的薪资记录数,二者可能不等 - 如果
AVG()和MIN()/MAX()差距极大,说明该组存在明显异常值,值得进一步检查原始数据 - 某些场景下(如监控指标),用
AVG(NULLIF(salary, 0))能主动排除 0 值干扰,但要注意业务含义是否允许
浮点精度和隐式类型转换陷阱
当被平均的字段是整型(如 salary INT),不同数据库处理方式不同:PostgreSQL 返回 numeric,MySQL 返回 DOUBLE,SQLite 返回浮点近似值。但如果你用 AVG() 算一个全是整数的列,结果未必是“看起来干净”的小数。
- 例如
AVG(1,2,3)在 PostgreSQL 中返回2.0000000000000000,而 MySQL 可能截断为2.00,取决于客户端或驱动设置 - 避免用
AVG(CAST(col AS DECIMAL(10,2)))强制精度——这会让计算过程变慢,且可能因中间舍入引入误差 - 真正要控制显示格式,应该在应用层或报表工具里做,而不是在 SQL 层硬转类型
分组平均看似简单,但字段语义、空值处理、精度预期和数据库版本差异,每处都可能悄悄改写结果。动手前先 SELECT * FROM table LIMIT 5 看一眼真实数据长什么样,比死记语法更重要。











