SQL题型之topn
数分 Top N 必背 3 个窗口函数
面试直接用,关键字全部小写,符合大厂规范:
row_number():唯一排名,同值不同号(1,2,3,4)rank():跳跃并列,同值同名次(1,1,3,4)dense_rank():连续并列,同值不跳号(1,1,2,3)
总结
- 基础 Top N →
order by + limit - 分组 Top N →
row_number() over(partition by ... order by ...) - 并列排名 →
dense_rank() - 连续 Top → 日期差分组法
基础表结构统一说明
员工表 employee
字段:emp_id 员工 id,dept_id 部门 id,emp_name 姓名,salary 薪资,entry_time 入职时间
订单表 order_info
字段:order_id 订单 id,user_id 用户 id,order_time 下单时间,pay_amount 支付金额,goods_type 商品类型
用户登录表 user_login
字段:user_id 用户 id,login_date 登录日期
练习平台:db<>fiddle
1 | create table order_info ( |
1. 全局取 top n
题目
员工表 employee
字段:emp_id 员工 id,dept_id 部门 id,emp_name 姓名,salary 薪资,entry_time 入职时间
查询员工表中薪资最高的前 6 名员工所有信息。
sql 答案
1 | select * |
2. 分组取每组 top1(row_number)
题目
员工表 employee
字段:emp_id 员工 id,dept_id 部门 id,emp_name 姓名,salary 薪资,entry_time 入职时间
查询每个部门内薪资最高的员工信息,每个部门只保留薪资最高 1 人,薪资相同只取一条。
sql 答案
1 | with temp as ( |
3. 分组取每组 top n
题目
订单表 order_info
字段:order_id 订单 id,user_id 用户 id,order_time 下单时间,pay_amount 支付金额,goods_type 商品类型
统计每个商品类型下,用户下单金额最高的前 3 笔订单数据。
sql 答案
1 | with temp as ( |
4. 并列排名不跳名次 dense_rank
题目
员工表 employee
字段:emp_id 员工 id,dept_id 部门 id,emp_name 姓名,salary 薪资,entry_time 入职时间
查询每个部门薪资排名前三的员工,薪资相同名次相同,不跳过排名,允许超出 3 条数据。
sql 答案
1 | with temp as ( |
5. 并列排名跳名次 rank
题目
员工表 employee
字段:emp_id 员工 id,dept_id 部门 id,emp_name 姓名,salary 薪资,entry_time 入职时间
查询全公司薪资排名前 5 的员工,同薪资同排名,排名向后顺延。
sql 答案
1 | with temp as ( |
6. 分组求用户总金额后取 top
题目
订单表 order_info
字段:order_id 订单 id,user_id 用户 id,order_time 下单时间,pay_amount 支付金额,goods_type 商品类型
统计每个用户累计支付总金额,找出累计消费最高的前 10 名用户及消费总额。
sql 答案
1 | select |
7. 每组取倒数 top n
题目
员工表 employee
字段:emp_id 员工 id,dept_id 部门 id,emp_name 姓名,salary 薪资,entry_time 入职时间
查询每个部门入职时间最晚的 2 名员工。
sql 答案
1 | with temp as ( |
8. 剔除重复后分组 top
题目
先统计每个用户在各商品类型下的下单次数,再取出每种商品类型下单次数最多的前 2 个用户。
sql 答案
1 | with user_cnt as ( |
9. 连续天数 top 进阶
题目
用户登录表 user_login
字段:user_id 用户 id,login_date 登录日期
统计每位用户连续登录天数,查询连续登录天数最多的前 8 位用户及其最长连续登录天数。
sql 答案
1 | with distinct_login as ( |
10. top n 占比统计
题目
订单表 order_info
字段:order_id 订单 id,user_id 用户 id,order_time 下单时间,pay_amount 支付金额,goods_type 商品类型
统计消费金额排名前 30% 用户的总消费金额,占全体用户总消费金额的比例。
sql 答案
1 | with user_total as( |
易错点
1 | select |
count(*) 是聚合函数(返回 1 行),count(*) over() 是窗口函数(每行都返回)
这个场景需要每行都知道”总人数”,所以必须用窗口函数 over()
count(*) over() as all_user -- ✅ 窗口函数,不是聚合函数 |