我有一个SQL Server 2012表,其中包含会话,开始和结束时间为2.我现在需要知道每分钟有多少会话活动,这意味着> = starttime和< = endtime。
实施例
Order_strUserId | Order_dtmInitiated | Order_dtmLastUpdated
s2ir1f8vqx | 2016-12-13 15:06:17.993 | 2016-12-13 15:06:59.723
4839m6lnjchn | 2016-12-13 15:09:42.807 | 2016-12-13 15:12:21.220
y7k3u6q1wjn | 2016-12-13 15:11:40.173 | 2016-12-13 15:12:01.630
sdc74a0ahid | 2016-12-13 15:14:06.013 | 2016-12-13 15:14:28.703
2pgj2ixpta9 | 2016-12-13 15:17:41.567 | 2016-12-13 15:17:42.063
qlfv4vmxdb | 2016-12-13 15:18:17.750 | 2016-12-13 15:18:47.227
y9jd24i59x5v | 2016-12-13 15:19:30.160 | 2016-12-13 15:19:30.607
9vb2d6u90hn | 2016-12-13 15:22:09.257 | 2016-12-13 15:22:09.743
第1行仅计入2016-12-13 15:06,2016-12-13 15:09和2016-12-13 15:12等每分钟第2行等。
我需要的是像
Time | ActiveSessions
2016-12-13 15:06 | 1
2016-12-13 15:09 | 1
2016-12-13 15:10 | 1
2016-12-13 15:11 | 2
2016-12-13 15:12 | 2
怎么做?
到目前为止,我的想法是按分钟计算UserId,然后添加计数所需的时间。但是我无法弄清楚如何计算它。
SELECT COUNT(t.UserSessionId) ,
DATEPART( yyyy , t.TimeInitiated) AS 'Year',
DATEPART(MM, t.TimeInitiated) 'Month',
DATEPART(DD, t.TimeInitiated) 'Day',
DATEPART(HH, t.TimeInitiated) 'Hour',
DATEPART(MI, t.TimeInitiated) 'Minute',
t.TimeNeeded
FROM ( SELECT DATEDIFF(MI, Order_dtmInitiated, Order_dtmLastUpdated) AS 'TimeNeeded',
Order_strUserId AS 'UserSessionId',
Order_dtmInitiated AS 'TimeInitiated'
FROM tblOrder ) t
GROUP BY DATEPART( yyyy , t.TimeInitiated), DATEPART(MM, t.TimeInitiated), DATEPART(DD, t.TimeInitiated), DATEPART(HH, t.TimeInitiated), DATEPART(MI, t.TimeInitiated), t.TimeNeeded
答案 0 :(得分:3)
您需要一个包含分钟的日历表
;WITH cte
AS (SELECT Min(Cast(Dateadd(minute, Datediff(minute, 0, Order_dtmInitiated), 0) AS SMALLDATETIME)) AS st_date,
Max(Cast(Dateadd(minute, Datediff(minute, 0, Order_dtmLastUpdated), 0) AS SMALLDATETIME)) ed_date
FROM Yourtable
UNION ALL
SELECT Dateadd(minute, 1, st_date),
ed_date
FROM cte
WHERE st_date < ed_date)
SELECT st_date,
Count(1)
FROM cte a
LEFT JOIN Yourtable b
ON a.st_date >= Cast(Dateadd(minute, Datediff(minute, 0, Order_dtmInitiated), 0) AS SMALLDATETIME)
AND a.st_date <= Cast(Dateadd(minute, Datediff(minute, 0, Order_dtmLastUpdated), 0) AS SMALLDATETIME)
GROUP BY st_date
OPTION (maxrecursion 0)
我已使用Recursive CTE
生成日期,但我更喜欢在数据库中创建Calendar
表,并在此类查询中使用它
答案 1 :(得分:0)
使用日历表,左连接数据
with Numbers as
(
select 0 as NN
union all
select NN+1
from Numbers
where NN < 99999
)
, Cal_table as
(
select dateadd(MI, NN, @StartTime) as By_Minute -- Throwing these in as parameters, but you can use a query to fill this bit in
from Numbers
where dateadd(MI, NN, @StartTime) <= @EndTime -- Throwing these in as parameters, but you can use a query to fill this bit in
)
select By_Minute, count(Order_strUserId) as ActiveUsers
from Cal_Table
left join MyTable
on Order_dtmInitiated <= By_Minute
and Order_dtmLastUpdated >= By_Minute
答案 2 :(得分:0)
您可以使用从每个会话行的第一分钟开始的递归CTE,添加一分钟直到达到该会话行的结束,然后计算每个时间戳的会话数:
-- Setup data:
DECLARE @rows TABLE(UserId VARCHAR(20), Initiated DATETIME, LastUpdated DATETIME)
INSERT INTO @rows VALUES
('s2ir1f8vqx' , '2016-12-13 15:06:17.993', '2016-12-13 15:06:59.723'),
('4839m6lnjchn', '2016-12-13 15:09:42.807', '2016-12-13 15:12:21.220'),
('y7k3u6q1wjn' , '2016-12-13 15:11:40.173', '2016-12-13 15:12:01.630'),
('sdc74a0ahid' , '2016-12-13 15:14:06.013', '2016-12-13 15:14:28.703'),
('2pgj2ixpta9' , '2016-12-13 15:17:41.567', '2016-12-13 15:17:42.063'),
('qlfv4vmxdb' , '2016-12-13 15:18:17.750', '2016-12-13 15:18:47.227'),
('y9jd24i59x5v', '2016-12-13 15:19:30.160', '2016-12-13 15:19:30.607'),
('9vb2d6u90hn' , '2016-12-13 15:22:09.257', '2016-12-13 15:22:09.743')
-- Do the work:
;WITH activity AS
(
SELECT r1.UserId, CAST(CONVERT(CHAR(17), r1.Initiated, 113) AS DATETIME) AS dt FROM @rows r1
UNION ALL
SELECT r2.UserId, DATEADD(minute, 1, dt) AS dt FROM activity INNER JOIN @rows r2 ON r2.UserId = activity.UserId WHERE DATEADD(minute, 1, dt) <= r2.LastUpdated
)
SELECT dt as Time, count(UserId) as ActiveSessions FROM activity
GROUP BY dt
OPTION (MAXRECURSION 10080) -- 10080 = 7*24*60 = user active every minute of one consecutive week (max is 32767 or ~ 3 weeks)
输出:
Time ActiveSessions
2016-12-13 15:06:00.000 1
2016-12-13 15:09:00.000 1
2016-12-13 15:10:00.000 1
2016-12-13 15:11:00.000 2
2016-12-13 15:12:00.000 2
2016-12-13 15:14:00.000 1
2016-12-13 15:17:00.000 1
2016-12-13 15:18:00.000 1
2016-12-13 15:19:00.000 1
2016-12-13 15:22:00.000 1
答案 3 :(得分:0)
其他方式,没有cte或日历表。只是想法,需要一些小的修复来满足您的需求
DECLARE
@dt_from DATETIME = '2016-12-13 15:06:17.993'
,@dt_to DATETIME = '2016-12-13 15:22:09.743'
,@cnt INT
,@mins INT = 2;
DECLARE @result TABLE([Time] DATETIME, [ActiveSessions] INT);
SET @dt_from = DATEADD(mi, DATEDIFF(mi, 0, @dt_from), 0);
SET @dt_to = DATEADD(mi, DATEDIFF(mi, 0, @dt_to), 0);
WHILE @dt_from <= @dt_to
BEGIN
SELECT @cnt = COUNT(*) FROM [YourTable]
WHERE
DATEADD(mi, DATEDIFF(mi, 0, [Order_dtmInitiated]), 0) BETWEEN @dt_from AND DATEADD(mi, @mins, @dt_from)
OR DATEADD(mi, DATEDIFF(mi, 0, [Order_dtmLastUpdated]), 0) BETWEEN @dt_from AND DATEADD(mi, @mins, @dt_from)
INSERT INTO @result([Time], [ActiveSessions])
VALUES (@dt_from, @cnt);
SET @dt_from = DATEADD(mi, @mins, @dt_from);
END;
SELECT * FROM @result;