group by 配合 max() 是唯一正解,单独用 select max(price) from products 只返回全表最大值;非聚合字段必须出现在 group by 中,否则报错;max() 忽略 null,全为 null 时才返回 null;取最大值对应行需用窗口函数而非硬套 max()。

GROUP BY 配合 MAX() 是唯一正解
单独写 SELECT MAX(price) FROM products 只会返回整张表的最大值,不是“每组”。要按类别、用户、日期等分组取最大值,必须搭配 GROUP BY。漏掉它,结果一定错。
常见错误是写成 SELECT name, MAX(price) FROM products GROUP BY category——name 既没在 GROUP BY 里,又不是聚合字段,MySQL 5.7+ 默认报错,PostgreSQL 和 SQL Server 直接拒绝执行。
- 正确写法:按什么分组,
SELECT列里非聚合字段就必须出现在GROUP BY中 - 例如查每个
category的最高价:SELECT category, MAX(price) FROM products GROUP BY category - 如果还想带出对应商品名,不能直接加
name,得用子查询或窗口函数(见下一条)
想同时拿到最大值那行的其他字段?别硬套 MAX()
MAX() 只返回值,不保留原始行上下文。比如“每个部门薪资最高的员工姓名”,MAX(salary) 能给出数字,但没法顺带把 name 拎出来——这是典型误区。
这时候该用窗口函数 ROW_NUMBER() 或 RANK(),而不是死磕 MAX():
SELECT name, department, salary
FROM (
SELECT name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
FROM employees
) t
WHERE rn = 1;
注意:ROW_NUMBER() 对相同薪资会强制排序(只取一个),RANK() 则会并列——选哪个取决于业务是否允许同分多人。
NULL 值会让 MAX() 返回 NULL?不一定
MAX() 会自动忽略 NULL,只在所有值都是 NULL 时才返回 NULL。这点和 SUM() 一致,但和 COUNT(*) 不同(后者统计行数,不管 NULL)。
- 如果某组所有
price都是NULL,MAX(price)结果就是NULL - 想把它转成 0,得用
COALESCE(MAX(price), 0) - 但要注意:如果业务中
0是有效值(比如免费商品),用COALESCE就可能掩盖数据异常
性能上,MAX() 在有索引时能走覆盖扫描
如果查询的是 MAX(created_at) FROM orders GROUP BY user_id,而表上有 (user_id, created_at) 复合索引,MySQL/PostgreSQL 可能直接从索引叶子节点取最大值,不用回表——这是隐式优化,但依赖索引顺序。
- 索引字段顺序必须匹配
GROUP BY+ 聚合字段,即先user_id后created_at - 反过来建索引
(created_at, user_id)就无法支持这个MAX()查询加速 - 用
EXPLAIN看执行计划里有没有Using index for group-by或类似提示










