用min()和max()配合group by可直接统计每组数值范围,二者自动忽略null;若全为null则结果为null,需用count()区分无数据与全null;索引优化建议创建(category, price)复合索引。

用 MIN() 和 MAX() 统计分组内数值范围
直接在 GROUP BY 后搭配 MIN() 与 MAX() 就能拿到每组的最小值和最大值,这是最常用也最可靠的方式。注意这两个函数会自动忽略 NULL,如果某组全为 NULL,结果就是 NULL,不是 0 或空字符串。
常见写法示例:
SELECT category, MIN(price) AS min_price, MAX(price) AS max_price FROM products GROUP BY category;
- 必须确保分组字段(如
category)和聚合字段(price)类型兼容——比如不能对文本列直接用MIN()求“数值范围”,除非它实际存的是数字或可隐式转换 - 若想同时算区间宽度(即
MAX() - MIN()),需确认该列是数值类型;否则会报错或返回意外结果(如字符串拼接) - 某些数据库(如 MySQL 5.7 默认模式)要求
SELECT中所有非聚合字段都必须出现在GROUP BY中,漏写会报错Expression #1 of SELECT list is not in GROUP BY clause
处理空值与边界异常时的注意事项
MIN() 和 MAX() 天然跳过 NULL,这通常是优点,但容易掩盖数据质量问题。比如某类商品价格全为 NULL,查询结果里这一行的 min_price 和 max_price 都是 NULL,看起来像没数据,其实是数据缺失。
- 想区分“无数据”和“全为 NULL”,可用
COUNT(price)辅助判断:若为 0,说明该组没有有效数值 - 若业务上
0是合法价格,但数据库里误存成了NULL,会导致范围被缩窄——得先清洗或用COALESCE(price, 0)补默认值(注意:补值后会影响真实范围) - PostgreSQL 和 SQL Server 支持
MIN() FILTER (WHERE ...),但 MySQL 不支持,跨库迁移时要注意语法兼容性
性能影响:索引是否生效取决于写法
单纯用 MIN()/MAX() + GROUP BY,在有合适索引时可以走索引扫描甚至索引跳跃(index skip scan),速度很快;但如果加了复杂条件或函数包装,就可能退化成全表扫描。
- 最佳索引形式是复合索引:
CREATE INDEX idx_category_price ON products(category, price); - 如果写成
MIN(ABS(price))或MAX(COALESCE(price, 0)),索引基本失效 - 在大数据量下,避免在
SELECT中同时查几十个分组的MIN/MAX还带ORDER BY—— 排序本身可能比聚合更耗资源
替代方案:窗口函数也能算组内极值,但用途不同
如果目标不是压缩行数(即不想要一行代表一组),而是保留原始行、只额外标出本组的最小/最大值,那就该用窗口函数:MIN(price) OVER (PARTITION BY category)。它不会合并行,也不会触发 GROUP BY 的严格模式限制。
- 窗口写法无法直接配合
GROUP BY使用,二者语义冲突;混用会报错 - MySQL 8.0+、PostgreSQL、SQL Server 都支持,但 SQLite 目前不支持窗口函数
- 如果只是要范围,别为了“看起来高级”强行用窗口函数——多占内存,还难读
实际用的时候,多数场景就老老实实用 GROUP BY 配 MIN()/MAX()。真正容易出问题的,是没检查原始数据里混着 NULL、非法字符,或者索引建错了位置。










