2017-01-13 29 views
0

內考慮下表:聚集的時間跨度MS SQL 2012

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 

的省略號是爲了簡潔的重複結果的緣故,而是應該有每個事件(1 48個結果在每半小時天)。您還會注意到,持續時間需要在半小時內計算。它不在示例數據中,但可以隨時有持續時間結束,而不僅僅是半小時。最後,我應該在23:30注意到'登錄'的結果。 ClientID 4在23:30-0:00半小時的2016-11-28和2016-11-29都有登錄事件。所以,持續時間總和都是這樣,但只計算一次客戶。

我有以下,這給了我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

DId沒有時間去測試整個分組,但我首先計算一個列,它存儲了00:00和當前時間之間的差值,除以30,以及 - 如果每天更改 - 添加相應的分鐘數(天數* 24(小時)* 60(分鐘))。這可能如下所示:(DATEDIFF(分鐘,'00:00:00.000',CONVERT(時間,StartDate))+(ISNULL(DATEDIFF(d,LAG(StartDate)OVER(ORDER BY ClientID,EventID,StartDate)) StartDate),0)* 1440))/ 30 - 可能通過PARTITION BY進行擴展。完成此操作後,您可以按此列進行分組和排序。 – Tyron78

回答

0
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;