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

如何在SQL中按多列对连续行进行分组

按多列对连续行分组的SQL解决方案

首先先把你提供的原始数据整理成更清晰的表格形式:

原始数据

DateUserTimeLocationServiceCount
1/1/2018Nick12:00Location AX1
1/1/2018Nick12:01Location AY1
1/1/2018John12:02Location BZ1
1/1/2018Harry12:03Location AX1
1/1/2018Harry12:04Location AX1
1/1/2018Harry12:05Location BY1
1/1/2018Harry12:06Location BX1
1/1/2018Nick12:07Location AX1
1/1/2018Nick12:08Location AY1

你要解决的是将连续行中User、Location、Service完全相同的行归为一组,并统计每组的总次数(或其他聚合指标),这是SQL里很常见的“连续相同属性分组”问题,核心思路是用窗口函数来标记分组边界,具体步骤如下:


步骤1:标记分组边界

首先用LAG()窗口函数对比当前行和上一行的User、Location、Service三个字段,只要其中一个字段不同,就标记为一个新分组的起点(用1表示),否则标记为0:

SELECT 
    *,
    CASE 
        -- 对比上一行的三个字段,只要有一个不同,就标记为新分组
        WHEN LAG(User) OVER (ORDER BY Date, Time) != User 
             OR LAG(Location) OVER (ORDER BY Date, Time) != Location 
             OR LAG(Service) OVER (ORDER BY Date, Time) != Service
        THEN 1 
        ELSE 0 
    END AS group_flag
FROM your_table_name
ORDER BY Date, Time;

这里用ORDER BY Date, Time是为了保证跨天的情况下排序依然正确,如果你确定数据都是同一天,可以只按Time排序。


步骤2:生成唯一分组ID

通过累积求和group_flag,我们可以得到每个连续组的唯一ID——每遇到一个标记为1的行,分组ID就会递增,这样相同连续组的行就会拥有同一个ID:

SELECT 
    *,
    -- 累积求和生成分组ID
    SUM(group_flag) OVER (ORDER BY Date, Time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS group_id
FROM (
    -- 嵌套第一步的查询
    SELECT 
        *,
        CASE 
            WHEN LAG(User) OVER (ORDER BY Date, Time) != User 
                 OR LAG(Location) OVER (ORDER BY Date, Time) != Location 
                 OR LAG(Service) OVER (ORDER BY Date, Time) != Service
            THEN 1 
            ELSE 0 
        END AS group_flag
    FROM your_table_name
) t1
ORDER BY Date, Time;

步骤3:按分组ID聚合统计

最后用group_id加上User、Location、Service分组,就能得到每个连续组的统计结果了:

SELECT 
    MIN(Date) AS date,
    User,
    Location,
    Service,
    MIN(Time) AS start_time,  -- 组内最早时间
    MAX(Time) AS end_time,    -- 组内最晚时间
    SUM(Count) AS total_count -- 组内总次数
FROM (
    SELECT 
        *,
        SUM(group_flag) OVER (ORDER BY Date, Time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS group_id
    FROM (
        SELECT 
            *,
            CASE 
                WHEN LAG(User) OVER (ORDER BY Date, Time) != User 
                     OR LAG(Location) OVER (ORDER BY Date, Time) != Location 
                     OR LAG(Service) OVER (ORDER BY Date, Time) != Service
                THEN 1 
                ELSE 0 
            END AS group_flag
        FROM your_table_name
    ) t1
) t2
GROUP BY group_id, User, Location, Service
ORDER BY start_time;

最终结果示例

执行上面的SQL后,你会得到类似这样的结果:

dateUserLocationServicestart_timeend_timetotal_count
1/1/2018NickLocation AX12:0012:001
1/1/2018NickLocation AY12:0112:011
1/1/2018JohnLocation BZ12:0212:021
1/1/2018HarryLocation AX12:0312:042
1/1/2018HarryLocation BY12:0512:051
1/1/2018HarryLocation BX12:0612:061
1/1/2018NickLocation AX12:0712:071
1/1/2018NickLocation AY12:0812:081

这样就完美实现了按多列对连续行分组统计的需求啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:17:19