0

我有一个问题,我一直在努力解决。如果有人可以帮助我,那就太好了。它位于 SQL Server 2012 上。

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

因此,我需要按发生的第一笔交易 + 1 小时对其进行分组,然后如果稍后发生另一组交易,我也需要将其分组。

例子:

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

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

如果这有点令人困惑,我深表歉意。

桌子:

用户 | 交易时间

0125 | 2016 年 3 月 6 日 12:24:01

0125 | 2016 年 3 月 6 日 12:34:06

0125 | 2016 年 3 月 6 日 13:22:02

0125 | 2016 年 3 月 6 日 16:24:10

0125 | 2016 年 3 月 6 日 17:10:08

输出:

用户 | 交易时间开始 | 交易时间结束 | 交易

0125 | 2016 年 3 月 6 日 12:24:01 | 2016 年 3 月 6 日 13:22:02 | 3

0125 | 2016 年 3 月 6 日 16:24:10 | 2016 年 3 月 6 日 17:10:08 | 2

4

2 回答 2

0

试试这个查询(我在 SQL Server 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

结果 :

在此处输入图像描述

于 2016-08-10T08:25:26.807 回答
0

或者,递归 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 
于 2016-08-10T09:30:01.800 回答