SQL 窗口函数排名的经典题,核心是理解「并列排名且连续」的规则

1. 窗口函数 DENSE_RANK()

这是解决本题的最直接方法,完全匹配题目要求:

  • 语法DENSE_RANK() OVER (ORDER BY score DESC)

  • 特性

    • 分数相同则排名相同(如两个 4.00 都排第 1)
    • 并列后排名不会跳过数字(如第 1 名之后直接是第 2 名)
  • 示例代码

    sql

    sql 复制代码
    SELECT
      score,
      DENSE_RANK() OVER (ORDER BY score DESC) AS `rank`
    FROM Scores;

2. 窗口函数 RANK()ROW_NUMBER() 的对比

表格

函数名 排名规则 示例结果(分数 4.00,4.00,3.85)
DENSE_RANK() 并列排名,排名连续 1, 1, 2
RANK() 并列排名,排名会跳过(有空隙) 1, 1, 3
ROW_NUMBER() 即使分数相同,也会分配连续序号 1, 2, 3

本题必须用 DENSE_RANK(),因为 RANK() 会产生排名空隙,ROW_NUMBER() 无法实现并列。

3. 子查询 / 自连接实现排名(传统方法)

如果不支持窗口函数,可以用自连接 模拟 DENSE_RANK()

sql

sql 复制代码
SELECT
  s1.score,
  (SELECT COUNT(DISTINCT s2.score)
   FROM Scores s2
   WHERE s2.score >= s1.score) AS `rank`
FROM Scores s1
ORDER BY s1.score DESC;
  • 逻辑:对每个分数 s1.score,统计有多少个不重复且大于等于它的分数,这个数量就是它的排名。
  • 优点:兼容所有 SQL 版本
  • 缺点:性能比窗口函数差,大数据量下效率低

4. 关键字与别名注意事项

  • rank 是 SQL 关键字,在 MySQL 中需要用反引号 rank 包裹作为列名,避免语法冲突。
  • 排序必须用 ORDER BY score DESC,保证结果按分数从高到低排列。

💡 易错点提醒

  • ❌ 使用 RANK():会导致排名出现空隙(如两个第 1 名后直接是第 3 名),不符合题目要求。
  • ❌ 使用 ROW_NUMBER():无法实现并列排名,相同分数会被分配不同序号。
  • ❌ 忘记给 rank 加反引号:在 MySQL 中会报语法错误,因为 rank 是保留字。
  • ✅ 优先使用 DENSE_RANK() 窗口函数,简洁且性能最优。

📌 总结

这道题的本质是理解 「并列且连续」的排名规则,核心知识点是:

  1. 窗口函数 DENSE_RANK() :专门用于实现「并列排名且连续」的场景,是本题最优解。
  2. 不同排名函数的区别DENSE_RANK()RANK()ROW_NUMBER() 的行为差异是面试高频考点。
  3. 传统自连接方法:在不支持窗口函数的环境下,通过子查询统计不重复分数来实现排名。
相关推荐
Asize1 小时前
JavaScript 数据类型解析:从 null 与 undefined 的迷思到栈堆内存真相
前端·javascript·面试
LDX前端校草1 小时前
position属性值及用法
前端·javascript·面试
hzhsec3 小时前
启明星辰(安全服务实习生)面试题
网络安全·面试
AI人工智能+电脑小能手4 小时前
【大白话说Java面试题 第115题】【并发篇】第15题:说一下悲观锁和乐观锁的区别?
java·开发语言·面试
Frank学习路上5 小时前
【C++】面试:STL容器与算法
c++·算法·面试
于指尖飞舞6 小时前
java后端面试题(常用集合极简)
java·开发语言·面试
AI人工智能+电脑小能手6 小时前
【大白话说Java面试题 第114题】【并发篇】第14题:说一下悲观锁的优点和缺点?
java·开发语言·面试
罗超驿6 小时前
13.Java多线程进阶:手动实现线程池与定时器机制详解
开发语言·面试·javaee
uhakadotcom6 小时前
结合着 fastapi 使用,anyio 通常可以如何使用 , 它和 uvloop 在性能上有啥差异
后端·面试·github
光影少年7 小时前
避免不必要渲染:PureComponent、memo、useMemo、useCallback
react.js·面试·掘金·金石计划