直接用 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 <p>这个逻辑清晰且跨数据库通用(MySQL、PostgreSQL、SQL Server 都支持)。注意几点:</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/ai/3587" title="Flova"><img src="https://img.php.cn/upload/ai_manual/001/246/273/178599552992970.png" alt="Flova" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/ai/3587" title="Flova" class="overflowclass">Flova</a> <p class="overflowclass">Flova是一款AI文本写作工具,全球首个一体化 AI 视频创作平台。</p> </div> <a rel="nofollow" href="/ai/3587" title="Flova" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>
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 本身不该“伪造”数据。










