直接用 ORDER BY salary DESC LIMIT 1,1 不可靠,因最高薪资重复时会返回仍为最高值的记录;真正需求是严格小于最高值的最大值,需先用 MAX() 找出最高薪资,再筛选小于它的最大值。

为什么直接用 ORDER BY salary DESC LIMIT 1,1 不可靠
很多初学者会写 SELECT salary FROM employees ORDER BY salary DESC LIMIT 1,1,看起来能跳过最高值取第二行。但问题在于:如果最高薪资有重复(比如两人都是 20000),LIMIT 1,1 会跳过第一个 20000,取到第二个 20000——这仍是最高值,不是“第二高”。真正要的是**严格小于最高值的最大值**,必须去重后再排序。
用 MAX() 和子查询排除最高值
最稳妥、兼容性最好的写法是先找出最高薪资,再查所有**小于该值**的记录里的最大值:
SELECT MAX(salary) AS second_highest_salary FROM employees WHERE salary < (SELECT MAX(salary) FROM employees);
这个逻辑清晰且跨数据库通用(MySQL、PostgreSQL、SQL Server 都支持)。注意几点:
WHERE salary 自动过滤掉所有最高值,包括重复项- 如果全表只有一种薪资(或为空),结果会返回
NULL,这是符合语义的——确实不存在第二高 - 不需要
DISTINCT,因为MAX()本身只返回一个标量
用 DENSE_RANK() 的写法(仅限支持窗口函数的数据库)
如果你用的是 MySQL 8.0+、PostgreSQL 或 SQL Server,可以用窗口函数更直观地表达“排名”:
SELECT salary AS second_highest_salary FROM ( SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rk FROM employees ) ranked WHERE rk = 2 LIMIT 1;
DENSE_RANK() 对相同薪资赋予相同排名(比如 [20000,20000,15000] → [1,1,2]),所以 rk = 2 确保拿到第二档薪资。但要注意:
- 若没有第二档(如全员同薪),查询不返回任何行,需额外处理空结果
-
LIMIT 1是为了防多行(比如多个员工同为第二高),但实际业务中常要列出全部第二高者,此时应去掉LIMIT - SQLite 直到 3.25+ 才支持窗口函数,旧版本不能用
别忽略空结果和 NULL 的语义
无论用哪种方法,都要意识到:第二高薪资可能根本不存在。比如表为空、只有一个人、所有人薪资相同。这时查询返回 NULL 或空集,不是 bug,而是正确结果。如果业务要求必须返回数字(例如默认 -1),得在外层加 COALESCE(..., -1) 或用 CASE WHEN 判断,但那是业务逻辑层的事,SQL 本身不该“伪造”数据。

















