如何运用SQL的MAX和MIN函数在报表中高效查询数据最大值和最小值?
- 内容介绍
- 相关推荐
本文共计721个文字,预计阅读时间需要3分钟。
直接说结论:
为什么 SELECT MAX(price), name FROM products 会报错?
因为 MAX() 是聚合函数,而 name 是非聚合字段。SQL 引擎无法确定你想要哪一行的 name —— 是价格最高那行的?还是随便一行的?不同数据库行为不一(MySQL 5.7+ 默认拒绝,PostgreSQL/SQL Server 直接报错)。
常见错误现象:ERROR: column "products.name" must appear in the GROUP BY clause or be used in an aggregate function
- 正确做法:要么加
GROUP BY,要么用子查询/窗口函数定位整行 - 如果真只想查“最贵商品的名字和价格”,该用
ORDER BY price DESC LIMIT 1,而不是硬套MAX() - 报表中常误以为“带 MAX 就能自动关联其他字段”,这是最大认知偏差
报表里怎么安全地显示“各分类最高价 + 对应商品名”?
不能靠 MAX(price), name GROUP BY category —— name 值是随机的(即使 MySQL 允许,也不保证是最高价那条)。得用窗口函数或关联子查询。
推荐写法(兼容 PostgreSQL / SQL Server / MySQL 8.0+):
SELECT category, name, price FROM ( SELECT category, name, price, ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC) AS rn FROM products ) t WHERE rn = 1;
- 用
ROW_NUMBER()标记每组内价格排序,rn = 1即最高价那条完整记录 - 若同一分类有多个相同最高价,
RANK()可保留并列,ROW_NUMBER()强制唯一 - 旧版 MySQL(5.7)只能用关联子查询,性能较差,需确保
(category, price)有复合索引
MIN/MAX 在 WHERE 和 HAVING 中的区别
初学者常混淆过滤时机:WHERE 过滤行,HAVING 过滤分组结果。想查“平均售价超 100 的分类中最低单价”,必须用 HAVING。
示例:
SELECT category, MIN(price) AS lowest_price FROM products GROUP BY category HAVING AVG(price) > 100;
-
WHERE price > 10是在分组前筛掉低价商品 HAVING MIN(price) 是在分组后筛掉那些组内最低价仍 ≥5 的分类- 报表导出时,若漏写
HAVING改成WHERE,结果集会多出大量无关分类
真正麻烦的是业务语义模糊时——比如“上月销量最高的产品”,要先明确是按“总销量”还是“单日峰值”,再决定用 SUM() 还是 MAX() 聚合,接着才处理“怎么带回产品信息”。这一步没理清,后面所有 MAX 都是空中楼阁。
本文共计721个文字,预计阅读时间需要3分钟。
直接说结论:
为什么 SELECT MAX(price), name FROM products 会报错?
因为 MAX() 是聚合函数,而 name 是非聚合字段。SQL 引擎无法确定你想要哪一行的 name —— 是价格最高那行的?还是随便一行的?不同数据库行为不一(MySQL 5.7+ 默认拒绝,PostgreSQL/SQL Server 直接报错)。
常见错误现象:ERROR: column "products.name" must appear in the GROUP BY clause or be used in an aggregate function
- 正确做法:要么加
GROUP BY,要么用子查询/窗口函数定位整行 - 如果真只想查“最贵商品的名字和价格”,该用
ORDER BY price DESC LIMIT 1,而不是硬套MAX() - 报表中常误以为“带 MAX 就能自动关联其他字段”,这是最大认知偏差
报表里怎么安全地显示“各分类最高价 + 对应商品名”?
不能靠 MAX(price), name GROUP BY category —— name 值是随机的(即使 MySQL 允许,也不保证是最高价那条)。得用窗口函数或关联子查询。
推荐写法(兼容 PostgreSQL / SQL Server / MySQL 8.0+):
SELECT category, name, price FROM ( SELECT category, name, price, ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC) AS rn FROM products ) t WHERE rn = 1;
- 用
ROW_NUMBER()标记每组内价格排序,rn = 1即最高价那条完整记录 - 若同一分类有多个相同最高价,
RANK()可保留并列,ROW_NUMBER()强制唯一 - 旧版 MySQL(5.7)只能用关联子查询,性能较差,需确保
(category, price)有复合索引
MIN/MAX 在 WHERE 和 HAVING 中的区别
初学者常混淆过滤时机:WHERE 过滤行,HAVING 过滤分组结果。想查“平均售价超 100 的分类中最低单价”,必须用 HAVING。
示例:
SELECT category, MIN(price) AS lowest_price FROM products GROUP BY category HAVING AVG(price) > 100;
-
WHERE price > 10是在分组前筛掉低价商品 HAVING MIN(price) 是在分组后筛掉那些组内最低价仍 ≥5 的分类- 报表导出时,若漏写
HAVING改成WHERE,结果集会多出大量无关分类
真正麻烦的是业务语义模糊时——比如“上月销量最高的产品”,要先明确是按“总销量”还是“单日峰值”,再决定用 SUM() 还是 MAX() 聚合,接着才处理“怎么带回产品信息”。这一步没理清,后面所有 MAX 都是空中楼阁。

