考虑下表:
CREATE TABLE dbo.Events (
[ClientID] int,
[EventID] int,
[EventName] varchar(50),
[StartDate] datetime,
[Duration] bigint
)
INSERT INTO dbo.Events(ClientID, EventID, EventName, StartDate, Duration)
VALUES (1, 1, 'Login', '2016-11-27 01:30:00.000', 86400000),
(2, 1, 'Login', '2016-11-27 00:30:00.000', 86400000),
(3, 1, 'Login', '2016-11-27 00:00:00.000', 86400000),
(4, 1, 'Login', '2016-11-28 23:30:00.000', 172800000),
(1, 2, 'Lock', '2016-11-27 23:30:00.000', 3600000),
(4, 2, 'Lock', '2016-11-28 23:30:00.000', 1800000)
如您所见,持续时间以毫秒为单位,可以跨越多天。
我需要查看已登录的客户端数量,已锁定的客户端数量以及给定日期范围内的持续时间。日期范围可以跨越一天/一周/一个月/一年,当它超过一天时,它应该仍然需要半小时。
最后,日期范围2016-11-28 00:00:00.000 - 2016-11-30 00:00:00.000的查询结果看起来如此(如果我错误计算SumDuration或CountClients,请为此道歉在某个地方,我手动完成了这个,但我认为这是正确的):
EventID EventName HalfHour SumDuration CountClients
--------------------------------------------------
1 'Login' 0:00 5400000 3
1 'Login' 0:30 3600000 2
1 'Login' 1:00 3600000 2
1 'Login' 1:30 1800000 1
... ... ... ... ...
1 'Login' 23:00 1800000 1
1 'Login' 23:30 3600000 1
2 'Lock' 0:00 3600000 2
2 'Lock' 0:30 1800000 1
... ... ... ... ...
2 'Lock' 23:00 1800000 1
2 'Lock' 23:30 3600000 2
省略号是为了重复结果的简洁,但每个事件应该有48个结果(一天中每半小时1个)。您还会注意到需要在半小时内计算持续时间。它不在示例数据中,但可以随时结束持续时间,而不仅仅是半小时标记。最后,我应该在23:30注意“登录”的结果。 ClientID 4在2016-11-28和2016-11-29期间在23:30-0:00半小时内举行了登录活动。因此,持续时间总和两者,但只计算客户一次。
我有以下内容,它为我提供了CountClients和SumDuration,但不会将其分成半小时的增量:
select E.EventID,
E.EventName,
count(*) as CountClients,
sum(datediff(millisecond, I.StartDate, I.EndDate)) as SumDuration
from dbo.Events as E
cross apply (
select max(T.StartDate) as StartDate,
min(T.EndDate) as EndDate
from (
values(@StartDate, @EndDate),
(E.StartDate, dateadd(millisecond, E.Duration, E.StartDate))
) as T(StartDate, EndDate)
) as I
where E.StartDate < @EndDate and
dateadd(millisecond, E.Duration, E.StartDate) > @StartDate
group by E.EventID,
E.EventName;
我如何将其分解为半小时的增量?
答案 0 :(得分:1)
DECLARE @FirstDay smalldatetime = '20161128',
@LastDay smalldatetime = '20161129';
;WITH TimeSlots(HalfHour) AS
(
SELECT TOP (24*2*DATEDIFF(DAY, @FirstDay, DATEADD(DAY,1,@LastDay)))
DATEADD(MINUTE, 30*(ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1), @FirstDay)
FROM master..spt_values
),
EventRange AS
(
SELECT EventID, EventName, StartDate,
EndDate = DATEADD(MILLISECOND, Duration, StartDate)
FROM dbo.Events
WHERE StartDate >= DATEADD(MILLISECOND, -Duration, @FirstDay)
AND StartDate < DATEADD(DAY, 1, @LastDay)
),
Combo AS
(
SELECT e.EventID, e.EventName,
HalfHourSlot = CONVERT(CHAR(5), CONVERT(datetime, CONVERT(time, t.HalfHour)), 108),
CASE
WHEN
e.StartDate <= t.HalfHour AND e.EndDate > t.HalfHour AND e.EndDate < DATEADD(minute, 30, t.HalfHour)
THEN DATEDIFF(MILLISECOND, e.EndDate, t.HalfHour)
WHEN
e.StartDate <= t.HalfHour AND e.EndDate > t.HalfHour AND e.EndDate >= DATEADD(minute, 30, t.HalfHour)
THEN 1800000
ELSE
0
END AS Duration
FROM TimeSlots AS t
CROSS JOIN EventRange AS e
)
SELECT EventID, EventName, HalfHour = HalfHourSlot,
SumDuration = SUM(Duration),
CountClients = SUM(CASE WHEN Duration>0 THEN 1 ELSE 0 END)
FROM Combo
GROUP BY EventID, EventName, HalfHourSlot
ORDER BY EventName DESC, HalfHour;