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

按首次订单10分钟间隔分组同客户订单的SQL实现问题

同一客户订单按10分钟窗口分组的SQL解决方案

需求说明

将同一客户的订单按如下规则分组:若订单发生在某组首次订单的10分钟内则归为该组,之后寻找下一个新的首次订单并重复分组逻辑。

示例数据

分组结果示例

Customer group  orders
   6        1      3
            2      4,5
            3      8
   7        1      9,10
            2      11,12
            3      13

原始订单数据

id  customer time
    3   6   2021-05-12 12:14:22.000000
    4   6   2021-05-12 12:24:24.000000
    5   6   2021-05-12 12:29:16.000000
    8   6   2021-05-12 13:01:40.000000
    9   7   2021-05-14 12:13:11.000000
    10  7   2021-05-14 12:20:01.000000
    11  7   2021-05-14 12:45:00.000000
    12  7   2021-05-14 12:48:41.000000
    13  7   2021-05-14 12:58:16.000000
    18  9   2021-05-18 12:22:13.000000
    25  15  2021-05-18 13:44:02.000000
    26  16  2021-05-17 09:39:02.000000
    27  16  2021-05-18 19:38:43.000000
    28  17  2021-05-18 15:40:02.000000
    29  18  2021-05-19 15:32:53.000000
    30  18  2021-05-19 15:45:56.000000
    31  18  2021-05-19 16:29:09.000000
    34  15  2021-05-24 15:45:14.000000
    35  15  2021-05-24 15:45:14.000000
    36  19  2021-05-24 17:14:53.000000

原代码问题

原CTE代码未在递归关联时按客户分组,导致case when d.StartTime > dateadd(minute, 10, c.first_time)逻辑出现跨客户比较的错误,无法正确分组。原代码如下:

with 
data as (select Customer,StartTime,Id, row_number() over(partition by Customer order by StartTime) rn from orders t),
cte as (
     select d.*, StartTime as first_time 
     from data d
     where rn = 1
     union all 
     select d.*, 
         case when d.StartTime > dateadd(minute, 10, c.first_time)
             then d.StartTime
             else c.first_time
         end
     from cte c 
    inner join data d on d.rn = c.rn + 1
 )
select c.*, dense_rank() over(partition by Customer order by first_time) grp 
from cte c;

解决方案

SQL Server版本

递归CTE需要在关联时加上Customer匹配,确保只在同一客户内递归计算分组基准时间:

WITH data AS (
    SELECT 
        Customer, 
        StartTime, 
        Id, 
        ROW_NUMBER() OVER(PARTITION BY Customer ORDER BY StartTime) rn 
    FROM orders t
),
cte AS (
    SELECT 
        d.Customer,
        d.StartTime,
        d.Id,
        d.rn,
        d.StartTime AS first_time
    FROM data d
    WHERE rn = 1
    UNION ALL
    SELECT 
        d.Customer,
        d.StartTime,
        d.Id,
        d.rn,
        CASE 
            WHEN d.StartTime > DATEADD(minute, 10, c.first_time) 
            THEN d.StartTime 
            ELSE c.first_time 
        END AS first_time
    FROM cte c
    INNER JOIN data d 
        ON d.Customer = c.Customer  -- *关键:按客户关联,避免跨客户递归*
        AND d.rn = c.rn + 1
)
SELECT 
    Customer,
    Id,
    StartTime,
    DENSE_RANK() OVER(PARTITION BY Customer ORDER BY first_time) AS grp
FROM cte
ORDER BY Customer, rn;

MySQL版本

MySQL 8.0+支持递归CTE,逻辑与SQL Server一致,仅时间函数略有差异:

WITH RECURSIVE data AS (
    SELECT 
        Customer, 
        StartTime, 
        Id, 
        ROW_NUMBER() OVER(PARTITION BY Customer ORDER BY StartTime) rn 
    FROM orders t
),
cte AS (
    SELECT 
        d.Customer,
        d.StartTime,
        d.Id,
        d.rn,
        d.StartTime AS first_time
    FROM data d
    WHERE rn = 1
    UNION ALL
    SELECT 
        d.Customer,
        d.StartTime,
        d.Id,
        d.rn,
        CASE 
            WHEN d.StartTime > DATE_ADD(c.first_time, INTERVAL 10 MINUTE) 
            THEN d.StartTime 
            ELSE c.first_time 
        END AS first_time
    FROM cte c
    INNER JOIN data d 
        ON d.Customer = c.Customer  -- *关键:按客户关联,避免跨客户递归*
        AND d.rn = c.rn + 1
)
SELECT 
    Customer,
    Id,
    StartTime,
    DENSE_RANK() OVER(PARTITION BY Customer ORDER BY first_time) AS grp
FROM cte
ORDER BY Customer, rn;

核心说明

  • 递归CTE中通过d.Customer = c.Customer确保只在同一客户内进行基准时间的递归计算,彻底解决跨客户比较的问题。
  • 最终通过DENSE_RANK()对同一客户的first_time分组,得到每个订单所属的组号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 11:35:24