如何使用SQL中的AVG函数计算某一列的平均值?

作者:袖梨 2026-06-23
AVG()是MySQL中计算数值列平均值的聚合函数,只接受INT、FLOAT、DECIMAL等数值类型列,自动忽略NULL值;若整列均为NULL则返回NULL而非0,不支持字符串或日期列直接计算。

AVG() 计算数值列平均值的基本用法

AVG() 只接受数值类型列,对 NULL 值自动忽略——这点很关键,不是报错,而是静默跳过。如果整列都是 NULL,结果返回 NULL,不是 0。

最常用写法是:SELECT AVG(price) FROM products;。注意不能写成 AVG(*)AVG(name),否则会报错 ERROR: function avg(character varying) does not exist(PostgreSQL)或类似提示(MySQL/SQL Server 各有不同但都拒绝非数值类型)。

  • 字符串、日期、布尔列必须先转换:比如 AVG(CAST(created_at AS DATE)) 没有意义,得转成时间戳差值再算
  • 想包含 NULL 当 0 处理?不行,AVG 不支持内置的“空值填充”,得用 COALESCE(price, 0) 包一层,但逻辑已改变(此时算的是“把 NULL 当 0 后的均值”,不是真实业务含义)
  • 聚合时若没加 GROUP BY,整张表只出一行结果;加了 GROUP BY category,就按分类各算一个平均值

AVG() 和 COUNT() 配合看数据质量

单独看 AVG(salary) 可能误导。比如结果是 8500,但实际可能只有 2 条非空记录,其余 98 行全是 NULL——这说明数据缺失严重。

推荐每次用 AVG() 时顺手加一列:COUNT(salary)COUNT(*) 对比:

SELECT   AVG(salary) AS avg_salary,  COUNT(salary) AS non_null_count,  COUNT(*) AS total_rowsFROM employees;

如果 non_null_count 远小于 total_rows,就得查清洗逻辑或上游录入问题,而不是直接拿平均值做报表。

浮点精度与类型隐式转换陷阱

AVG() 的返回类型取决于输入列:如果原列是 INT,多数数据库(如 PostgreSQL)仍返回 NUMERICDOUBLE PRECISION,但 MySQL 在某些旧版本中可能截断小数位。

  • 显式控制精度:用 ROUND(AVG(score), 2) 确保两位小数,避免前端展示出现 89.33333333333333
  • 整数列求平均后想保留小数?别依赖默认行为。安全做法是先乘 1.0:AVG(score * 1.0)(SQL Server),或用 AVG(CAST(score AS DECIMAL(10,2)))(PostgreSQL/MySQL)
  • WHERE 条件写在 AVG 外面不生效:错误写法 AVG(CASE WHEN status='active' THEN salary END) 是对的;错误写法 AVG(salary) WHERE status='active' 语法直接报错

窗口函数中用 AVG() 实时对比均值

想看每个员工工资比部门平均高多少?别用子查询关联,直接上窗口函数:AVG(salary) OVER (PARTITION BY dept_id)

这样一行语句就能同时拿到个体值和群体基准:

SELECT   name,  salary,  AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg_salary,  salary - AVG(salary) OVER (PARTITION BY dept_id) AS diff_from_dept_avgFROM employees;

注意:窗口版 AVG() 仍跳过 NULL,且 PARTITION BY 分组内若全为 NULL,对应行的 dept_avg_salary 也是 NULL。没有 ORDER BY 子句时,默认是整分组全量计算,不是累积平均。

真正容易被忽略的是:AVG() 在 GROUP BY 和窗口函数中行为一致(都跳 NULL),但语义完全不同——前者压缩行数,后者保持原行数。混用时务必确认你到底要聚合还是对标。

相关文章

精彩推荐