描述
现有牛客刷题表`questions_pass_record`,请查询每天刷题通过数最多的前二名用户id和刷题数,输出按照日期升序排序,查询返回结果名称和顺序为
date|user_id|pass_count

SELECT date, user_id, pass_count
FROM (
SELECT user_id, pass_count,date,
ROW_NUMBER() OVER (PARTITION BY date ORDER BY pass_count DESC) AS rk
FROM questions_pass_record
) AS t
WHERE rk
第一步:内层子查询(核心逻辑)
SELECT
user_id,
pass_count,
date,
ROW_NUMBER() OVER (PARTITION BY date ORDER BY pass_count DESC) AS rk
FROM questions_pass_record
这是整个查询的核心,使用了 窗口函数(Window Function)。
✅ ROW_NUMBER() OVER (...) 是什么?
这是一个排序函数,它会给每一行分配一个唯一的序号(从 1 开始)。
我们来拆解括号里的内容:
🟦 PARTITION BY date
- 意思是:按日期分组。
- 把数据按照
date切成多个“小块”(每一天一块)。 - 每一天内部独立进行排序。
👉 就像把全班同学按“考试日期”分成不同考场,每个考场单独排名。
🟨 ORDER BY pass_count DESC
- 在每个“日期分组”内部,按
pass_count(通过题数)从高到低排序。 -
DESC表示降序(大 → 小),所以通过题数最多的排在最前面。
🟩 ROW_NUMBER() ... AS rk
- 给每行打上一个排名编号:
- 当天 pass_count 最高的 →
rk = 1 - 第二高的 →
rk = 2 - 第三高的 →
rk = 3,以此类推
- 当天 pass_count 最高的 →
📌 注意:ROW_NUMBER() 是“连续且不重复”的,即使两个人分数一样,也会强行分出 1 和 2。
第二步:外层查询(筛选 Top 2)
SELECT date, user_id, pass_count
FROM ( ... 上面的结果叫 t ... )
WHERE rk
- 我们把内层查询的结果当作一张临时表
t。 - 然后从中选出
rk 的记录,也就是: - 每天排名前两名的用户。
三种排序方式详解
1. ROW_NUMBER()
- 特点:给每一行分配一个唯一的序号,从 1 开始,连续递增。
-
相同值怎么办?即使
pass_count相同(如 B 和 C 都是 9),也会强行分出先后(2 和 3)。 -
适用场景:
- 需要唯一编号;
- 不允许重复排名;
- 比如“取前 N 条记录”,即使并列也要限制数量。
💡 小贴士:如果有并列数据,
ROW_NUMBER()的顺序是不确定的(除非再加ORDER BY细化)。
2. RANK()
- 特点:标准竞赛排名规则。
- 相同值:并列同一名次;
- 后续名次:跳过相应的数量。
👉 例子中:
- A 是第 1 名;
- B 和 C 并列第 2 名;
- D 是第 4 名(因为前面有 3 个人,但只有两个名次被占用:1 和 2)。
🏆 就像奥运会:两人并列银牌,就没有铜牌。
-
适用场景:
- 想体现“并列排名”;
- 接受名次跳跃;
- 比如“找出所有成绩不低于第2名的用户”。
3. DENSE_RANK()
- 特点:紧密排名,不跳过名次。
- 相同值:并列同一名次;
- 后续名次:+1。
👉 例子中:
- A:第 1 名;
- B 和 C:第 2 名;
- D:第 3 名。
🎯 更像是“等级制”:第1级、第2级、第3级……
-
适用场景:
- 想知道“这是第几档水平”;
- 不希望名次断层;
- 比如“取前3个等级的用户”。
文章来源于互联网:SQL93 查询每天刷题通过数最多的前二名用户id和刷题数
5bei.cn大模型教程网










