SQL 中排名与去重的经典题

25 阅读2分钟

image.png

🔍 核心知识点解析

这道题是 SQL 中排名与去重的经典题,主要考察以下几个关键知识点:


1. 去重(DISTINCT)

  • 题目要求 “第二高的不同薪水”,所以必须先对 salary 字段去重,避免重复值干扰排名。

  • 语法示例:

    sql

    SELECT DISTINCT salary FROM Employee
    

2. 排序与分页(ORDER BY + LIMIT)

  • 要找到 “第二高”,需要先按薪水降序排列,再取第 2 条记录。

  • LIMIT 语法:LIMIT offset, count,其中 offset 是偏移量(从 0 开始),count 是返回条数。

  • 取第 2 高:LIMIT 1, 1(跳过 1 条,取 1 条)。

  • 语法示例:

    sql

    SELECT DISTINCT salary
    FROM Employee
    ORDER BY salary DESC
    LIMIT 1, 1
    

3. 处理空结果(IFNULL / MAX / 子查询)

  • 当不存在第二高薪水时(如只有 1 条记录或所有记录薪水相同),需要返回 null

  • 方法 1:使用 IFNULL 包裹子查询(MySQL 语法):

    sql

    SELECT IFNULL(
      (SELECT DISTINCT salary
       FROM Employee
       ORDER BY salary DESC
       LIMIT 1, 1),
      NULL
    ) AS SecondHighestSalary
    
  • 方法 2:使用 MAX 函数,当子查询无结果时,MAX 会返回 null

    sql

    SELECT MAX(salary) AS SecondHighestSalary
    FROM (
      SELECT DISTINCT salary
      FROM Employee
      ORDER BY salary DESC
      LIMIT 1, 1
    ) AS temp
    

4. 窗口函数进阶(RANK / DENSE_RANK)

  • 更通用的解法是使用窗口函数,适合处理 “第 N 高” 的场景:

    sql

    SELECT DISTINCT salary AS SecondHighestSalary
    FROM (
      SELECT salary,
             DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
      FROM Employee
    ) AS temp
    WHERE rnk = 2
    
    • DENSE_RANK():并列排名时不会跳过序号(如 300、200、200,排名为 1、2、2)。
    • RANK():并列排名时会跳过序号(如 300、200、200,排名为 1、2、2、4)。

💡 易错点提醒

  • ❌ 忘记去重:直接 ORDER BY salary DESC LIMIT 1,1 会把重复薪水算成多条,导致排名错误。
  • ❌ 不处理空结果:当只有 1 条记录时,子查询会返回空集,外层查询需要显式返回 null
  • ✅ 优先用 DISTINCT + LIMIT 解决基础场景,窗口函数适合更复杂的排名需求。

📌 总结

这道题的本质是理解 “去重 → 排序 → 取第 N 条 → 处理空结果” 的完整流程。掌握了 DISTINCTLIMITIFNULL/MAX,就能解决绝大多数 “第 N 高” 的 SQL 问题。