MAX()和MIN()是标准SQL聚合函数,可直接计算单列最大/最小值,天然忽略NULL;整列NULL时返回NULL,不能用于WHERE子句,需配合HAVING、子查询或窗口函数实现行级查询。

直接用 MAX() 和 MIN() 就能拿到单列极值
不需要子查询、也不用排序取首尾——MAX() 和 MIN() 是标准 SQL 聚合函数,对一列数值(或可比较类型)直接计算最大/最小值。它们天然忽略 NULL,这点很关键:如果整列全是 NULL,结果就是 NULL,不是报错。
常见错误是误以为它们能返回整行数据。比如想查“销售额最高的人是谁”,只写 SELECT MAX(sales) FROM employees,结果只拿到数字,没拿到对应姓名。这时候就得配合 GROUP BY 或子查询/窗口函数,不能只靠 MAX() 单打独斗。
查最大/最小值时遇到 NULL 怎么办
MAX() 和 MIN() 默认跳过 NULL,这是 ANSI 标准行为,所有主流数据库(PostgreSQL、MySQL、SQL Server、SQLite)都一致。但要注意两个边界情况:
- 整列都是
NULL→ 返回NULL,不是 0 或空字符串 - 列类型混合(比如
VARCHAR字段存数字字符串)→ 比较按字典序,'9' > '10'成立,结果不符合数值预期 - 想把
NULL当成最小值处理?得先用COALESCE(col, -999999)或CASE WHEN转换,再套MIN()
在 WHERE 条件里不能直接用 MAX() 或 MIN()
聚合函数不能出现在 WHERE 子句中,因为 WHERE 执行在分组前,而 MAX() 需要先完成分组聚合。你会收到类似 "Invalid use of group function" 或 "column 'xxx' must appear in the GROUP BY clause" 的错误。
正确做法是:
- 用
HAVING替代WHERE(当已有GROUP BY) - 用子查询:比如
SELECT * FROM orders WHERE amount = (SELECT MAX(amount) FROM orders) - 用窗口函数(更高效,尤其要查多条并列最大值时):
SELECT * FROM (SELECT *, RANK() OVER (ORDER BY amount DESC) rnk FROM orders) t WHERE rnk = 1
性能和索引怎么配合 MAX()/MIN()
如果只是查整表的 MAX(id) 或 MIN(created_at),且该列上有 B-Tree 索引,大多数数据库(如 MySQL InnoDB、PostgreSQL)能直接走索引最左/最右叶子节点,复杂度接近 O(log n),不用全表扫描。
但以下情况会失效:
- 对表达式用聚合:比如
MAX(ABS(price)),除非建函数索引(PostgreSQL 支持,MySQL 8.0+ 有限支持) - 列上有
WHERE条件但没命中索引:比如SELECT MAX(value) FROM t WHERE status = 'active',而索引是(value)不是(status, value) - 使用了
GROUP BY且分组键未索引,聚合过程可能变慢
查单列极值看着简单,但真要兼顾正确性、NULL 处理、条件过滤和性能,每个环节都容易漏掉隐含约束。











