You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于时间序列的驾驶员用车记录自定义分组排名需求

嘿,我完全懂你的问题——你要的不是那种把同一车辆下所有同驾驶员记录都归为一组的排名,而是要追踪连续的驾驶时段:只要同一辆车的相邻记录驾驶员变了,排名就得更新,对吧?

你之前用的DENSE_RANK() OVER (PARTITION BY CAR_ID, DRIVER_ID ORDER BY DT)之所以会出问题,是因为它不管驾驶员是不是连续驾驶的——哪怕中间插了别的驾驶员,之后再回来的同个驾驶员也会和之前的记录归为同一组,这就是那两个标记#的元素被混在一起的原因。

要实现你要的“连续相同驾驶员才同排名”的效果,我们需要用岛屿问题的经典解法,分三步来做:

步骤1:标记前一条记录的驾驶员ID

首先,我们用LAG()函数,按车辆分组、时间排序,拿到当前记录的上一条记录的驾驶员ID,这样就能对比前后是不是同一个人:

LAG(DRIVER_ID) OVER (PARTITION BY CAR_ID ORDER BY DT) AS prev_driver

步骤2:生成分组切换标记

接下来,我们判断当前驾驶员和上一条是不是不同——如果不同(或者是第一条记录,没有上一条),就标记为1,否则标记为0:

CASE 
    WHEN DRIVER_ID != LAG(DRIVER_ID) OVER (PARTITION BY CAR_ID ORDER BY DT) 
         OR LAG(DRIVER_ID) OVER (PARTITION BY CAR_ID ORDER BY DT) IS NULL 
    THEN 1 
    ELSE 0 
END AS group_flag

这个标记的作用是:每一次驾驶员切换(包括第一条记录),就生成一个“新分组开始”的信号。

步骤3:累加标记得到连续排名

最后,我们按车辆分组、时间排序,对这个group_flag做累加——累加的结果就是我们要的连续排名:

SUM(group_flag) OVER (PARTITION BY CAR_ID ORDER BY DT) AS RES

(注:大多数数据库里,ORDER BY在窗口函数里默认的范围就是从分区开头到当前行,所以可以不用写ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,不过写上也没问题)

把这些整合起来,完整的SQL大概是这样:

WITH driver_segments AS (
    SELECT 
        DT,
        CAR_ID,
        DRIVER_ID,
        CASE 
            WHEN DRIVER_ID != LAG(DRIVER_ID) OVER (PARTITION BY CAR_ID ORDER BY DT) 
                 OR LAG(DRIVER_ID) OVER (PARTITION BY CAR_ID ORDER BY DT) IS NULL 
            THEN 1 
            ELSE 0 
        END AS group_flag
    FROM your_driving_table -- 替换成你的表名
)
SELECT 
    DT,
    CAR_ID,
    DRIVER_ID,
    SUM(group_flag) OVER (PARTITION BY CAR_ID ORDER BY DT) AS RES
FROM driver_segments
ORDER BY CAR_ID, DT;

这样运行后,同一车辆下连续的同一个驾驶员会得到相同的RES值,一旦驾驶员切换,RES就会自动递增,完全符合你要的类似DENSE_RANK但只针对连续记录的需求。

内容的提问来源于stack exchange,提问作者yet_another_programmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:12:43