MAX()是聚合函数,须配合GROUP BY或用于单行结果集;直接混用非聚合字段会报错;查最大值对应整行需用窗口函数、子查询或LIMIT,不同数据库方案不同。

MAX()函数的基本用法和常见错误
MAX() 是聚合函数,必须配合 GROUP BY 或用于无分组的单行结果集。直接在普通 SELECT 中混用非聚合字段会报错,比如 SELECT name, MAX(age) FROM users 在大多数数据库(如 PostgreSQL、SQL Server)中会拒绝执行——因为 name 没有明确归属哪一行。
- 正确写法:只查最大值,
SELECT MAX(age) FROM users - 要查“年龄最大的那条完整记录”,不能只靠
MAX(),得用子查询或窗口函数 - 注意
NULL值会被自动忽略;全列为NULL时返回NULL
如何查出“最大值对应的那一整行”?
这是最常被误解的点。MAX() 本身不保留原始行上下文,所以不能直接“连带取出姓名、ID 等”。常见解法取决于数据库支持程度:
- MySQL 8.0+ / PostgreSQL / SQL Server:用窗口函数
ROW_NUMBER() OVER (ORDER BY age DESC),取rn = 1 - 老版本 MySQL(5.7 及之前):用自连接或相关子查询,例如
SELECT * FROM users u1 WHERE u1.age = (SELECT MAX(age) FROM users)—— 但注意:多个同为最大值的记录会全部返回 - SQLite:不支持窗口函数,推荐用
ORDER BY age DESC LIMIT 1(仅取一条,不保证稳定性)
GROUP BY 场景下误用 MAX() 的典型陷阱
当按部门统计最高薪资时,有人会写 SELECT dept, MAX(salary), name FROM employees GROUP BY dept,期望拿到每个部门里工资最高者的姓名——这在 MySQL 5.7 开启 ONLY_FULL_GROUP_BY 时会报错,在关闭状态下可能返回任意一个 name,而非对应最高工资的那个人。
- 安全做法:先用子查询找出每个部门的
MAX(salary),再关联原表匹配完整记录 - 更高效做法(推荐):用
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC),然后过滤rn = 1 - 别依赖 MySQL 的“隐式 GROUP BY 行为”,它不可移植且语义模糊
性能与数据类型注意事项
MAX() 在有索引的列上能走索引扫描(特别是 B-Tree 索引的最右端),但前提是该列是查询条件的一部分或单独使用。如果写成 MAX(ABS(price)) 这类表达式,就无法利用 price 上的普通索引。
- 字符串列用
MAX()返回字典序最大值,不是长度最长的,例如MAX('apple', 'banana')→'banana' - 日期列没问题:
MAX(created_at)得到最后时间 - 复合条件慎用:想查“近30天内最大订单金额”,记得先加
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days',否则全表扫描代价高
真正麻烦的是“最大值 + 对应行其他字段”这个需求,它看起来简单,实际涉及语义歧义(多个并列最大值怎么选)、执行计划差异、以及不同 SQL 方言的能力边界。动手前先确认你的数据库版本和严格模式是否开启,比硬套语法更重要。

















