GROUP BY 配合 MIN() 是分组求最小值的唯一可靠方式,单独用 MIN() 仅返回全表最小值;若需获取最小值所在完整行,须用窗口函数或关联子查询,不可依赖非聚合字段与 MIN() 同行。

GROUP BY 配合 MIN() 是唯一可靠方式
单独用 MIN() 只返回整张表的最小值,没法按组算。必须搭配 GROUP BY 才能分组求最小值。常见错误是漏写 GROUP BY 或只写部分字段,导致结果不可预期或报错(比如 MySQL 5.7 严格模式下会拒绝执行)。
实操建议:
- SELECT 列表中所有非聚合字段,都必须出现在
GROUP BY子句里 - 如果想同时查出最小值对应的完整行(比如哪条记录的 price 最低),
MIN()本身做不到,得换用窗口函数或关联子查询 - 注意 NULL 值:
MIN()自动忽略 NULL,但如果某组全为 NULL,结果就是 NULL
MIN() 在 WHERE 中不能直接用于分组过滤
有人想“查出每组最小值大于 10 的那些组”,直接写 WHERE MIN(price) > 10 会报错——因为 WHERE 执行在分组前,MIN() 还没计算。
正确做法是用 HAVING:
SELECT category, MIN(price) AS min_price FROM products GROUP BY category HAVING MIN(price) > 10;
关键区别:WHERE 过滤行,HAVING 过滤分组后的结果。别把 HAVING 当成可选语法,它是必需的。
MySQL 8.0+ 用窗口函数获取最小值所在整行
如果不仅要最小值,还要知道这行的 id、name 等其他字段,用 MIN() + GROUP BY 会丢失信息。这时该上窗口函数:
SELECT id, name, category, price
FROM (
SELECT id, name, category, price,
MIN(price) OVER (PARTITION BY category) AS min_price_in_cat
FROM products
) t
WHERE price = min_price_in_cat;
注意点:
-
PARTITION BY category相当于分组,但不压缩行数 - 这个写法可能返回多行(同组多个 price 并列最小),如需唯一一行,得加
ROW_NUMBER()或用ORDER BY ... LIMIT 1子查询 - 旧版 MySQL(
NULL 和数据类型影响 MIN() 结果
MIN() 对字符串、日期、数字都有效,但行为有差异:
- 字符串按字典序比较,
MIN(name)返回字母最靠前的名字,不是长度最短的 - 日期类型直接比时间先后,没问题;但若存成字符串(如 '2023-01-01'),也按字典序,只要格式统一就 OK
- 混合类型(比如字段定义为
VARCHAR却存数字)会导致隐式转换异常,MIN()可能返回意外结果,务必检查字段类型 - 聚合时遇到 NULL 不报错,但容易让人误以为“没数据”,其实可能是数据本身含 NULL
最常被忽略的是字段类型和 NULL 处理逻辑——它们不会报错,却让结果悄悄偏离预期。

















