因WHERE salary < MAX(salary)在聚合前执行,语法错误;应先用子查询获取最大值,再筛选小于该值的最大salary。

用 MAX() 排除最大值后查第二高,为什么结果常为空?
直接用 WHERE salary 会报错 —— 聚合函数不能出现在 <code>WHERE 子句里。更常见的是写成子查询形式,但若表中所有值相同(比如全是 100),SELECT MAX(salary) FROM employees WHERE salary 就返回空,因为没有满足 <code> 的记录。
- 必须用子查询先算出最大值,再在外层过滤
- 要处理重复最大值:如果最高分有多个
95,第二高仍是95还是下一个不同值?业务上通常指「去重后的第二高」 - 空结果不等于错误,而是数据本身不存在第二高值,需确认是否要返回
NULL或加COALESCE
嵌套查询 + MAX() 的标准写法及等效替代
最稳妥的写法是两层子查询:内层取最大值,外层在排除该值的集合中再取最大值。它逻辑清晰、兼容所有 SQL 标准(MySQL、PostgreSQL、SQL Server 都支持)。
SELECT MAX(salary) AS second_highest FROM employees WHERE salary < (SELECT MAX(salary) FROM employees);
- 这个写法天然跳过重复最大值,自动实现「去重后第二高」
- 如果只要第 N 高且 N 较大,性能会明显下降,此时应改用
ROW_NUMBER()或DENSE_RANK() - MySQL 8.0+ 和 PostgreSQL 可用
(SELECT DISTINCT salary ORDER BY salary DESC LIMIT 1 OFFSET 1),但 SQLite 不支持LIMIT在子查询中直接嵌套
遇到 NULL 或全 NULL 列时的行为
MAX() 对全 NULL 列返回 NULL,而 salary 永远为 <code>UNKNOWN,导致外层查询无结果。这不是 bug,是三值逻辑的必然表现。
- 若字段允许
NULL,且你希望忽略它们,显式加上WHERE salary IS NOT NULL - 测试时可用
SELECT COUNT(*) FROM employees WHERE salary IS NOT NULL确认有效数据量 - 某些场景下需要兜底,例如:
COALESCE((SELECT MAX(salary) FROM employees WHERE salary ,但括号嵌套已够深,可考虑用 CTE 拆解
为什么不用 ORDER BY ... LIMIT 1,1?
MySQL 中 ORDER BY salary DESC LIMIT 1 OFFSET 1 看似简洁,但它不跳过重复值 —— 如果数据是 [100, 100, 90],它返回 100(第二个元素),而非真正意义上的第二高 90。
-
LIMIT offset, row_count是位置偏移,不是排名偏移 - 要按排名取值,必须配合窗口函数或去重子查询,否则语义错误
- Oracle 和 SQL Server 不支持
LIMIT,这种写法不具备移植性
LIMIT 带偏,先想清楚语义,再选语法。

















