彼此在一小时内完成交易(不是按小时分组)
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
我有一个问题困扰了我一段时间。 如果有人可以帮助我,那就太好了。 它在 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