AVG() 必须配合 GROUP BY 使用,否则报错;非聚合字段必须出现在 GROUP BY 中;AVG() 忽略 NULL 但不忽略 0 或空字符串;需注意类型转换、精度截断及 WHERE/HAVING 的分工。

AVG() 必须配合 GROUP BY 使用,否则报错
单独写 SELECT AVG(price) FROM products 没问题,但一旦加上其他非聚合字段(比如 category),不加 GROUP BY 就会出错——MySQL 会报 ERROR 1055,PostgreSQL 直接拒绝执行。这不是语法疏忽,是 SQL 标准强制要求:每个非聚合列都必须出现在 GROUP BY 中。
常见错误写法:SELECT category, AVG(price) FROM products → 缺少 GROUP BY category,必然失败。
- 正确写法:
SELECT category, AVG(price) FROM products GROUP BY category - 如果想按多个维度分组,比如类别+品牌:
SELECT category, brand, AVG(price) FROM products GROUP BY category, brand - 注意:
GROUP BY的字段顺序不影响结果,但会影响排序(除非显式加ORDER BY)
NULL 值会被自动忽略,但空字符串或 0 不算 NULL
AVG() 只计算非 NULL 的数值,这点很省心;但容易误判的是:字段值为 ''(空字符串)、'0'(字符串零)、或数值 0,这些都不会被跳过——只要不是 NULL,就参与平均值计算。
比如价格字段类型是 VARCHAR,存了 ' ' 或 '',AVG(price) 会尝试转成数字,多数数据库转成 0,拉低平均值。
- 检查是否有隐式转换干扰:
SELECT COUNT(*), COUNT(price), AVG(price) FROM products—— 如果COUNT(*)明显大于COUNT(price),说明有NULL;如果两者相等但平均值异常低,查查有没有'0'或空字符串 - 稳妥做法:显式过滤掉无效值,如
AVG(NULLIF(price, 0))(排除 0)或AVG(CASE WHEN price > 0 THEN price END)
浮点精度和类型截断可能影响结果
AVG() 返回类型取决于输入字段:整数列(如 INT)的平均值在 MySQL 中默认返回 DECIMAL,但精度有限;PostgreSQL 会返回 numeric,更精确。不过跨库迁移时容易发现“同样数据,平均值差 0.01”——大概率是小数位数被截断了。
例如:AVG(score) 对 [95, 96, 97] 计算得 96.0000,但如果字段是 TINYINT,某些旧版本 MySQL 可能只保留 1 位小数。
- 控制精度:用
ROUND(AVG(price), 2)显式保留两位小数 - 避免隐式类型转换:确保参与计算的列是数值型(
INT,DECIMAL),别用VARCHAR存数字 - 注意除零风险:虽然
AVG()在空组返回NULL而非报错,但若后续用该结果做除法,仍需COALESCE(..., 0)防止NULL传播
WHERE 和 HAVING 的分工必须分清
WHERE 过滤行,HAVING 过滤分组——这是最容易混淆的点。想算“电子产品中价格高于 100 的商品平均价”,不能写成 HAVING price > 100,因为 price 是原始行字段,不在分组后上下文中。
典型错误:SELECT category, AVG(price) FROM products GROUP BY category HAVING price > 100 → 报错或逻辑错误,price 不可直接在 HAVING 中引用(除非是聚合结果)。
- 正确方式一(先筛再分组):
SELECT category, AVG(price) FROM products WHERE price > 100 GROUP BY category - 正确方式二(筛分组结果):
SELECT category, AVG(price) FROM products GROUP BY category HAVING AVG(price) > 100 - 混合使用也常见:先
WHERE排除非活跃商品(status = 'active'),再GROUP BY,最后用HAVING筛掉平均价太低的品类
GROUP BY 位置,比反复试错快得多。

















