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

如何用SQL按时间间隔分组多笔硬币交易(LAG函数疑问)

问题描述

处理加油区机器(洗车机/充气机等)的硬币交易数据,每枚硬币对应一条交易记录,需要将间隔小于3分钟的多条记录合并为一个交易。已尝试用LAG函数判断上一笔交易是否在3分钟内,但无法对多行进行分组(可能包含1条或多条前置记录)。

当前尝试代码

select  t1.*,
        datediff(second, PreviousVendDateTime, VendDateTime) as SecondsDiff,
        case when datediff(second, PreviousVendDateTime, VendDateTime) < 360 then 1 else 0 end as SameTransaction
from 
        (select       mct.TransactionID,
                      mct.MachineID,
                      mct.VendDateTime,
                      mct.Amount,
                      lag(mct.VendDateTime, 1)
                        over(partition by mct.MachineID order by mct.VendDateTime) as PreviousVendDateTime
        from          Machines as m
        join          MCI_CashTrans as mct
        on            mct.MachineID = m.MachineID
        and           mct.MachineSerial = m.MachineSerial
        join          Account as a
        on            m.AccountNo = a.AccountNo
        join          MachineType as mt
        on            m.MachineTypeID = mt.MachineTypeID) as t1
order by MachineID, VendDateTime

结果示例

TransactionIDMachineIDVendDateTimeAmountPreviousVendDateTimeSecondsDiffSameTransaction
25180592197772023-06-01 19:01:541.002023-06-01 18:53:584760
25190595597772023-06-01 19:02:091.002023-06-01 19:01:54151
25183570227772023-06-01 21:20:411.002023-06-01 19:02:0983120
25183628757772023-06-01 21:23:011.002023-06-01 21:20:411401
25183692517772023-06-01 21:29:121.002023-06-01 21:23:013710
25183695997772023-06-01 21:29:381.002023-06-01 21:29:12261
25183697377772023-06-01 21:29:511.002023-06-01 21:29:38131
25183698947772023-06-01 21:30:040.502023-06-01 21:29:51131
25183700277772023-06-01 21:30:170.502023-06-01 21:30:04131
25183701717772023-06-01 21:30:311.002023-06-01 21:30:17141
25183703387772023-06-01 21:30:441.002023-06-01 21:30:31131
25184048847772023-06-01 21:46:111.002023-06-01 21:30:449270
解决方案

核心思路是通过累计求和生成交易组ID:当SameTransaction为0时代表新交易开始,累计这些0的数量就能得到唯一的分组标识,同组内的记录会共享同一个ID。

完整SQL代码

WITH base_data AS (
    SELECT 
        mct.TransactionID,
        mct.MachineID,
        mct.VendDateTime,
        mct.Amount,
        LAG(mct.VendDateTime, 1) OVER (PARTITION BY mct.MachineID ORDER BY mct.VendDateTime) AS PreviousVendDateTime
    FROM Machines AS m
    JOIN MCI_CashTrans AS mct 
        ON mct.MachineID = m.MachineID AND mct.MachineSerial = m.MachineSerial
    JOIN Account AS a 
        ON m.AccountNo = a.AccountNo
    JOIN MachineType AS mt 
        ON m.MachineTypeID = mt.MachineTypeID
),
transaction_groups AS (
    SELECT 
        *,
        DATEDIFF(second, PreviousVendDateTime, VendDateTime) AS SecondsDiff,
        CASE 
            WHEN DATEDIFF(second, PreviousVendDateTime, VendDateTime) < 360 THEN 1 
            ELSE 0 
        END AS SameTransaction,
        -- 累计生成分组ID:每遇到新交易(间隔≥3分钟),分组ID加1
        SUM(CASE 
                WHEN DATEDIFF(second, PreviousVendDateTime, VendDateTime) < 360 THEN 0 
                ELSE 1 
            END) OVER (PARTITION BY MachineID ORDER BY VendDateTime) AS TransactionGroupID
    FROM base_data
)
-- 按交易组聚合,得到合并后的交易记录
SELECT 
    MachineID,
    TransactionGroupID,
    MIN(VendDateTime) AS TransactionStart,
    MAX(VendDateTime) AS TransactionEnd,
    SUM(Amount) AS TotalAmount,
    -- 拼接所有关联的原始交易ID
    STRING_AGG(CAST(TransactionID AS VARCHAR), ', ') AS RelatedTransactionIDs
FROM transaction_groups
GROUP BY MachineID, TransactionGroupID
ORDER BY MachineID, TransactionStart;

代码说明

  1. base_data CTE:获取基础交易数据,用LAG函数拿到上一笔交易的时间,和你之前的逻辑一致。
  2. transaction_groups CTE:
    • 计算时间差和是否属于同一交易的标识;
    • 关键的SUM(...) OVER (...):当当前记录和上一笔间隔≥3分钟时加1,否则加0,累计后得到的TransactionGroupID就是每个交易组的唯一标识,同一组内的所有记录ID相同。
  3. 最终聚合:按MachineID和TransactionGroupID分组,计算交易的起止时间、总金额,还可以拼接所有关联的原始交易ID。

这样就能把间隔小于3分钟的连续交易合并成一个组,解决分组问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:14:52