SQL里怎么搞最大最小值查询,有啥技巧和坑要注意
- 问答
- 2026-01-12 16:48:20
- 3
在SQL里查最大最小值,最直接的想法就是用 MAX() 和 MIN() 函数,比如你想知道公司里谁的工资最高,直接 SELECT MAX(工资) FROM 员工表; 就行了,但实际工作中,问题往往没那么简单,你通常不只是想知道那个孤零零的数字,而是想知道“工资最高的那个人是谁?”或者“每个部门工资最高的人是谁?”,这就涉及到一些技巧和容易踩坑的地方了。
核心技巧:如何找到“最值”对应的整行数据
这是最常见也最经典的坑,很多人会下意识地这么写:
SELECT * FROM 员工表 WHERE 工资 = MAX(工资);
这么写是错的,因为 WHERE 子句不能直接使用聚合函数(像 MAX, MIN, AVG 这些)来处理整张表。WHERE 是针对每一行数据进行过滤的,而 MAX(工资) 需要先扫描所有行才能得出结果,这个执行顺序上有冲突。
正确的做法有几种,各有优劣:
-
子查询法(最直观) 先通过一个子查询找到最大值是多少,然后再用这个值去主查询里匹配。
SELECT * FROM 员工表 WHERE 工资 = (SELECT MAX(工资) FROM 员工表);要注意的坑:如果有多个人都是最高工资,这条语句会把他们都查出来,这可能是你想要的,也可能不是,如果你只想要一个(比如随便一个,或者要最早入职的那个),那就需要额外增加排序和限制条件,会复杂一些。 -
排序取一法(
LIMIT或TOP) 先把数据按工资从高到低排序,然后只取第一条。 在 MySQL 里是:SELECT * FROM 员工表 ORDER BY 工资 DESC LIMIT 1;在 SQL Server 里是:SELECT TOP 1 * FROM 员工表 ORDER BY 工资 DESC;要注意的坑:这个方法非常高效,尤其表很大的时候,但最大的坑就是,如果最高工资有两个人,它只会返回排序后最先遇到的那一条,会漏掉另一个最高工资的人,所以这个方法只在“确定最大值唯一”或“只取一个代表也行”的场景下使用。 -
窗口函数法(现代且强大) 如果你用的数据库比较新(MySQL 8.0+, PostgreSQL, SQL Server 2005+ 等都支持),强烈推荐使用窗口函数
ROW_NUMBER()或RANK()。 比如查每个部门工资最高的那个人:SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY 部门 ORDER BY 工资 DESC) as 排名 FROM 员工表 ) AS 临时表 WHERE 排名 = 1;这个语句的意思是:先按部门分组(PARTITION BY 部门),在每个部门内部按工资降序排名,然后只取每个部门里排名第一的人。 要注意的坑:ROW_NUMBER()即使工资相同也会排出1,2,3,不会出现并列第一,如果你希望允许并列,应该用RANK()函数,它会在工资相同时给出相同的排名,选择哪个函数取决于你的业务需求。
分组查询中的最值(按类别找最值)
“查找每个部门的最低工资”这种需求非常普遍,这时就要用到 GROUP BY。
SELECT 部门, MIN(工资) AS 最低工资 FROM 员工表 GROUP BY 部门;
要注意的坑:
SELECT后面的字段:除了聚合函数(MIN(工资))之外,其他出现在SELECT里的字段(部门),必须同时出现在GROUP BY子句里,如果你写了SELECT 部门, 姓名, MIN(工资)... GROUP BY 部门,就会报错,因为数据库不知道在同一个部门里,多个“姓名”中该显示哪一个。- 过滤分组的结果:你不能用
WHERE来过滤MIN(工资),因为WHERE在分组前执行,如果你想找“最低工资超过10000的部门”,需要用HAVING子句:SELECT 部门, MIN(工资) ... GROUP BY 部门 HAVING MIN(工资) > 10000;,一定要分清WHERE(过滤行)和HAVING(过滤组)的区别。
NULL 值的坑
这是一个容易被忽略但很重要的点。MAX() 和 MIN() 函数在计算时会自动忽略 NULL 值,这大部分时候是好事,但如果你没意识到,可能会产生误解。
你有一个“成绩”字段,有些学生没考试是 NULL。MAX(成绩) 会返回有成绩的学生中的最高分,这没问题,但如果你想知道成绩的“范围”,用 MAX(成绩) - MIN(成绩),如果所有学生都没考试(成绩全是 NULL),这个计算会返回 NULL,而不是 0,你在程序里处理结果时,需要考虑到这种可能性,做好 NULL 值的判断。
性能上的考虑
- 索引是王道:如果你的查询是
WHERE 工资 = (SELECT MAX(工资)...)或者ORDER BY 工资 DESC LIMIT 1,那么在“工资”这个字段上建立索引会极大地提升查询速度,数据库可以非常快地从索引的头部或尾部直接读取最大值,而不需要扫描整张表。 - 子查询 vs 连接:在一些复杂的场景下,比如需要关联其他表才能确定“最值”的条件,有时用
JOIN的方式写出来的 SQL 会比用子查询性能更好(反之亦然),这取决于数据库查询优化器的能力,没有绝对的标准,如果发现查询慢,可以尝试换一种写法,并用EXPLAIN命令查看执行计划。
总结一下关键点:
- 找最值对应的行,别在
WHERE里直接用MAX/MIN,用子查询、排序取一或窗口函数。 - 排序取一法(
LIMIT/TOP)简单快,但要小心它可能漏掉并列的最值。 - 按组查询最值时,分清
GROUP BY和HAVING的用法。 - 窗口函数
ROW_NUMBER()/RANK()是处理“各组内最值”问题的利器,功能强大。 - 始终记得
MAX/MIN会忽略 NULL,确保你的业务逻辑能接受这一点。 - 在用于排序和筛选的字段上加索引,能有效提升性能。
这些技巧和注意事项掌握了,日常工作中绝大部分关于最大最小值的查询就都能应对了。

本文由畅苗于2026-01-12发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/79421.html
