sum 和 avg 必须配合 GROUP BY 使用,否则结果无意义
单独写
SELECT SUM(price), AVG(price) FROM orders;看似能出结果,但实际只返回一行聚合值,完全丢失了数据分组意图。真实业务中几乎总是要按时间、类别、用户等维度汇总——比如“每个品类的平均售价”或“每位买家的订单总额”。这时候漏掉
GROUP BY category或
GROUP BY user_id,得到的就是全表一把抓的假汇总,后续分析会直接跑偏。
常见错误现象:
SELECT product_id, SUM(amount) FROM sales;—— MySQL 5.7+ 默认报错(
sql_mode=only_full_group_by开启),因为
product_id不在聚合函数里也没出现在
GROUP BY中。 正确写法示例:
SELECT category, SUM(price) AS total, AVG(price) AS avg_price FROM products GROUP BY category;如果真想查全表总和+均值,显式写清楚意图:
SELECT 'all' AS scope, SUM(price), AVG(price) FROM products;注意 NULL 值:sum/avg 自动忽略 NULL,但若整列都是 NULL,sum 返回 NULL,avg 返回 NULL(不是 0)
max/min 在 WHERE 子句里不能直接当条件用
新手常写
WHERE price = MAX(price),这会报错:
Invalid use of group function。因为聚合函数不能出现在 WHERE 中——WHERE 执行时还没做分组和聚合。
真正需要“找出价格最高的那条记录”,得换思路:
用子查询:SELECT * FROM products WHERE price = (SELECT MAX(price) FROM products);用 ORDER BY + LIMIT 更高效(尤其有索引时):
SELECT * FROM products ORDER BY price DESC LIMIT 1;如果要找“每类中最贵的商品”,必须搭配窗口函数或关联子查询,例如:
SELECT * FROM products p1 WHERE price = (SELECT MAX(price) FROM products p2 WHERE p2.category = p1.category);
数值类型隐式转换会让 sum/avg 结果意外失真
如果字段定义是
VARCHAR但存了数字(如
'12.5',
'30'),MySQL 会尝试转成 double 计算,但遇到非法字符就截断或转成 0。比如字段值为
'10kg',sum 会当成
10;值为
'abc'就变成
0。 检查真实类型:
DESCRIBE table_name;确认目标列是
DECIMAL、
FLOAT或
INT,不是字符串类型 临时补救(不推荐长期用):
SUM(CAST(price AS DECIMAL(10,2))),但 CAST 遇到脏数据仍可能报错或静默失败 更安全的做法:先用
WHERE price REGEXP '^[0-9]+(\.[0-9]+)?$'过滤掉非数字值再聚合
count(*) 和 count(字段) 行为差异极大,别混用
虽然标题问的是 sum/avg/max/min,但实操中常有人顺手写
COUNT(price)想统计“有价格的记录数”,却误以为等价于
COUNT(*)。两者语义完全不同:
COUNT(*)统计所有行(包括 price 为 NULL 的行)
COUNT(price)只统计
price IS NOT NULL的行 如果字段允许 NULL,且业务关心“有效数据量”,必须用
COUNT(字段);如果关心“总记录数”,只能用
COUNT(*)
性能上,
COUNT(*)在 InnoDB 中通常最快(引擎可优化),而
COUNT(字段)必须读取该字段判断是否为 NULL,开销略大。
聚合函数本身不难,难的是明确你要回答的问题到底是什么——是“整体趋势”还是“分组对比”,是“极端值定位”还是“有效数据覆盖度”。一旦问题模糊,SQL 写出来大概率在逻辑层就错了,再怎么调语法也救不回来。
