分组Top N 问题

今天面试,面试官给了这样一个场景:
有两张表,一张表存放 车队ID,班组ID,司机ID
另一种表存放 司机ID,运营时间,运营里程

要查询出 7月份每个车队每个班组里的 Top 3

这就要用到 ROW_NUMBER() 函数

首先按需求建两张表

CREATE TABLE demo_of_topn_car
(
companyid varchar(8),
classid varchar(8),
driverid varchar(8)
)

CREATE TABLE demo_of_topn_operating
(
driverid varchar(8),
operadate datetime,
mileage DECIMAL(5,2)
)

第一步思路 先把每个车队每个班组每个司机的运营总和计算出来

SELECT car.companyid,car.classid,operat.driverid,sum(mileage) mileage from
(
SELECT companyid,classid FROM demo_of_topn_car GROUP BY companyid,classid
) car
LEFT JOIN
(
SELECT a.companyid,a.classid,a.driverid,b.mileage 
FROM demo_of_topn_car a
LEFT JOIN demo_of_topn_operating b on a.driverid = b.driverid
) operat ON car.companyid = operat.companyid AND car.classid = operat.classid
GROUP BY car.companyid,car.classid,operat.driverid

然后对结果集进行分组排序

SELECT companyid,classid,driverid,row_number() over (PARTITION by companyid,classid ORDER BY mileage desc) rid from (
SELECT car.companyid,car.classid,operat.driverid,sum(mileage) mileage from
(
SELECT companyid,classid FROM demo_of_topn_car GROUP BY companyid,classid
) car
LEFT JOIN
(
SELECT a.companyid,a.classid,a.driverid,b.mileage 
FROM demo_of_topn_car a
LEFT JOIN demo_of_topn_operating b on a.driverid = b.driverid
) operat ON car.companyid = operat.companyid AND car.classid = operat.classid
GROUP BY car.companyid,car.classid,operat.driverid
ORDER BY mileage DESC
) t1 

切记:求 Top N 都是倒序

最后需要在外面嵌套一层,或者用with

with res as (
SELECT companyid,classid,driverid,row_number() over (PARTITION by companyid,classid ORDER BY mileage desc) rid from (
SELECT car.companyid,car.classid,operat.driverid,sum(mileage) mileage from
(
SELECT companyid,classid FROM demo_of_topn_car GROUP BY companyid,classid
) car
LEFT JOIN
(
SELECT a.companyid,a.classid,a.driverid,b.mileage 
FROM demo_of_topn_car a
LEFT JOIN demo_of_topn_operating b on a.driverid = b.driverid
) operat ON car.companyid = operat.companyid AND car.classid = operat.classid
GROUP BY car.companyid,car.classid,operat.driverid
ORDER BY mileage DESC
) t1 )  

SELECT * from res where rid <= 3

不知道大家有什么更好的办法,欢迎指导。 :)

### 如何在 MySQL 中实现分组 Top N 查询 #### 使用子查询结合 `LIMIT` 实现分组 Top N 查询 对于不支持窗口函数的 MySQL 版本,一种常见的方式是利用子查询配合 `LIMIT` 来获取各分组内的前几项记录。这种方法的核心在于构建一个嵌套查询结构,外部查询负责最终的结果展示,而内部查询则专注于按指定标准排序并截取所需数量的数据。 ```sql SELECT t1.* FROM table_name AS t1 JOIN ( SELECT group_column, MIN(id) as min_id FROM table_name GROUP BY group_column ) AS t2 ON t1.group_column = t2.group_column AND t1.id >= t2.min_id ORDER BY t1.group_column, t1.sort_column DESC LIMIT N; ``` 此代码片段展示了如何基于某个字段(`group_column`)进行分组,并选取每组内按照另一字段(`sort_column`)降序排列后的前N条记录[^3]。 #### 利用用户定义变量追踪排名位置 另一种策略涉及引入用户自定义变量来动态计算每一行在其所属分组中的相对位次。这种方式允许更灵活地控制筛选逻辑以及处理更为复杂的业务场景: ```sql SET @curGroup := ''; SET @rank := 0; SELECT * FROM( SELECT *, IF(@curGroup = group_column, @rank:=@rank+1, IF(@curGroup:=group_column, @rank:=1, @rank)) AS rank FROM table_name ORDER BY group_column ASC, sort_column DESC ) ranked_rows WHERE rank <= N; ``` 上述脚本首先初始化两个会话级别的变量——分别用来存储当前正在处理的分组标识符及其成员计数器;接着通过IF表达式更新这些变量的状态变化情况,从而达到为各行分配适当等级的目的;最后仅保留那些满足预设阈值条件(即不超过给定的最大排行数目)的项目作为输出结果集的一部分。 #### 执行顺序注意事项 值得注意的是,在编写任何类型的 SQL 查询之前都应该清楚了解各个组成部分之间的相互作用关系。根据已知的信息可知,MySQL 的默认解析流程遵循着一定的先后次序:首先是 `FROM` 和其下的连接操作,其次是 `WHERE` 进行初步过滤,随后才是 `GROUP BY` 完成分组统计工作,紧接着执行聚合运算与列的选择 (`SELECT`) ,再往后便是依据 `ORDER BY` 对整个集合实施全局性的排序安排,直至最后一刻才由 `LIMIT` 施加限制措施决定实际返回多少条目[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值