group by配合max()和min()是最直接解法,必须与group by一起使用且select中所有非聚合字段都需出现在group by列表中;若需获取极值对应完整记录,应使用窗口函数或关联子查询而非仅依赖max()/min()。

GROUP BY 配合 MAX() 和 MIN() 是最直接解法
想按某个字段分组后取每组的极值,MAX() 和 MIN() 必须和 GROUP BY 一起用,单独在 SELECT 中混用非聚合字段会报错(比如 MySQL 8.0+ 默认 SQL mode 下提示 Expression #1 of SELECT list is not in GROUP BY clause)。
常见错误是写成 SELECT name, MAX(score) FROM students 却没加 GROUP BY name —— 这要么报错,要么返回不可靠的 name 值(取决于 SQL mode 和引擎)。
- 必须明确写出分组依据:
GROUP BY category、GROUP BY user_id等 - SELECT 中所有非聚合字段都得出现在 GROUP BY 列表里
- 如果只想看极值不关心其他字段,就只 SELECT 聚合结果 + 分组字段
需要同时拿到最大值对应那条完整记录?别用 MAX()/MIN() 直接查
MAX() 和 MIN() 只返回值,不带回原始行的其他列(比如时间戳、ID、描述)。想查“销售额最高的订单是哪一笔”,光靠 MAX(amount) 不够。
典型做法是用窗口函数或子查询:
- MySQL 8.0+ / PostgreSQL / SQL Server:用
ROW_NUMBER() OVER (PARTITION BY category ORDER BY amount DESC)标记每组第一行,再过滤rn = 1 - 旧版 MySQL(5.7):用关联子查询,例如
WHERE amount = (SELECT MAX(amount) FROM orders o2 WHERE o2.category = orders.category),但要注意多值并列时可能返回多行 - 避免用
ORDER BY amount DESC LIMIT 1配合 GROUP BY —— 这语法不合法,SQL 不允许在 GROUP BY 查询里混用 LIMIT
NULL 值会影响 MAX()/MIN() 吗?会影响,但方式很固定
MAX() 和 MIN() 自动忽略 NULL,这点和 SUM() 一致。但如果整组数据全为 NULL,结果就是 NULL。
实际中容易踩坑的是字段类型隐式转换:
- 字符串字段用
MAX(name)返回的是字典序最大值,不是长度最长的 - 日期字段
MIN(created_at)没问题,但若列含非法日期(如'0000-00-00'),某些 MySQL 版本可能报错或返回意外结果 - 混合数字和字符串(比如
'10'和'2')参与比较时,MySQL 可能转成数字比大小,PostgreSQL 则直接报错
性能关键点:给分组字段和排序字段建联合索引
当表很大时,GROUP BY category ORDER BY amount DESC 这类查询容易慢。单纯在 category 上建索引不够,因为数据库还得对每组数据排序找极值。
更高效的方式是建覆盖索引:
- MySQL:用
INDEX (category, amount)—— B+Tree 索引天然支持按 category 分组后快速定位每组最大/最小 amount - 如果还要查其他字段(比如
SELECT category, MAX(amount), product_id),考虑把product_id加进索引末尾,避免回表 - 注意:
MIN()和MAX()在索引有序的前提下可走索引最左/最右节点,速度接近 O(1),但前提是索引顺序匹配查询逻辑
没有索引时,GROUP BY 会触发临时表 + 文件排序,数据量一过百万行,响应时间就明显变长。











