彼此在一小时内完成交易(不是按小时分组)

Get transactions done in an hour from each other (not group by hour)

我有一个问题困扰了我一段时间。 如果有人可以帮助我,那就太好了。 它在 SQL Server 2012 上。

我有一个 table,其中包含一定数量的交易和用户 ID。 我需要计算一个小时内的所有交易,并按用户 ID 分组。它也不能按 datepart(hh,1,SomeColumn) 分组,因为那样它只会处理发生在 16:00 - 16:59.

的交易

所以我需要按发生的第一笔交易 + 1 小时对其进行分组,如果之后发生了另一组交易,我也需要将其分组。

示例:

第一笔交易是 13:45 - 我需要计算从 13:45 - 14:45 发生的所有交易。按用户 ID 分组。

然后我需要计算在 16:09 - 17:09 发生的所有交易,这些交易按同一用户 ID 分组。

如果有点混乱,我深表歉意。

Table:

User | TransactionTime

0125 | 03/06/2016 12:24:01

0125 | 03/06/2016 12:34:06

0125 | 03/06/2016 13:22:02

0125 | 03/06/2016 16:24:10

0125 | 03/06/2016 17:10:08

输出:

User | TransactionTimeStart | TransactionTimeEnd | Transactions

0125 | 03/06/2016 12:24:01 | 03/06/2016 13:22:02 | 3

0125 | 03/06/2016 16:24:10 | 03/06/2016 17:10:08 | 2

试试这个查询(我在 SQL 服务器 2012 上测试)

CREATE TABLE #tmp (usr INT,TransactionTime DATETIME)
CREATE TABLE #result (startTime DATETIME , endTime DATETIME)

INSERT INTO #tmp VALUES 
    (0125,'03/06/2016 12:24:01'),(0125,'03/06/2016 12:34:06')
    ,(0125,'03/06/2016 13:22:02'),(0125,'03/06/2016 16:24:10')
    ,(0125,'03/06/2016 17:10:08')

DECLARE @minTime DATETIME = (SELECT MIN(TransactionTime) FROM #tmp)
DECLARE @maxTime DATETIME = (SELECT MAX(TransactionTime) FROM #tmp)

DECLARE @tmp DATETIME = @minTime

WHILE @tmp < @maxTime
BEGIN
    IF @tmp > @maxTime 
        INSERT INTO #result VALUES (@tmp, DATEADD(HOUR,1,@maxTime))
    ELSE
        INSERT INTO #result VALUES (@tmp, DATEADD(HOUR,1,@tmp))
    SET @tmp = DATEADD(HOUR,1,@tmp)
END

SELECT DISTINCT t.usr
    ,r.startTime
    ,r.endTime
    ,COUNT(1) OVER (PARTITION BY r.startTime,r.endTime,t.usr) AS [cnt]
FROM #result r
LEFT JOIN #tmp t ON t.TransactionTime BETWEEN r.startTime AND r.endTime
WHERE t.usr IS NOT NULL


DROP TABLE #tmp
DROP TABLE #result

结果:

或者,递归 CTE 解决方案

with dat as (
    -- sample data
    select * from (
        values
            (0125,cast('20160306 12:24:01' as datetime))
            ,(0125,cast('20160306 12:34:06' as datetime))
            ,(0125,cast('20160306 13:22:02' as datetime))
            ,(0125,cast('20160306 16:24:10' as datetime))
            ,(0125,cast('20160306 17:10:08' as datetime)) 
            ,(0125,cast('20160306 18:24:10' as datetime))
            ,(0125,cast('20160306 19:10:08' as datetime)) 
        )t([User],TransactionTime)
), hdrs as (
    select [User], TransactionTime= min(TransactionTime), rn = cast(0 as bigint)
    from dat
    group by [User]
    union all
    select dat.[User], dat.TransactionTime
         , rn = hdrs.rn + row_number() over(partition by hdrs.[user], hdrs.TransactionTime order by dat.TransactionTime) - 1
    from dat
    join hdrs on dat.[User]= hdrs.[User] and
    dat.TransactionTime > dateadd(HOUR,1,hdrs.TransactionTime)    
)
select hdrs.[User],hdrs.TransactionTime, n = count(*) 
from hdrs
join dat on rn = 0 and dat.TransactionTime between hdrs.TransactionTime and dateadd(HOUR,1,hdrs.TransactionTime)
group by hdrs.[User],hdrs.TransactionTime