This isn't very efficient, but I think it does what you want. You might want to check for fencepost errors on the interactions between the logins and logouts and the reporting periods.DECLARE @RepStartTime datetime, @RepEndTime datetime, @RepFreq intSET @RepStartTime = '2001-01-01 00:00:00'SET @RepEndTime = '2002-01-01 00:00:00'SET @RepFreq = 3600SELECT HStart, @RepFreq - SUM( CASE WHEN InTime IS NULL THEN 0 ELSE DATEDIFF(second, CASE WHEN OutTime > HStart THEN OutTime ELSE HStart END, CASE WHEN InTime < HEnd THEN InTime ELSE HEnd END) END )FROM ( SELECT HStart, DATEADD(second, @RepFreq, HStart) HEnd FROM ( SELECT DATEADD(second, N * @RepFreq, @RepStartTime) HStart FROM Numbers WHERE N * @RepFreq < DATEDIFF(second, @RepStartTime, @RepEndTime) ) a) hoursLEFT JOIN ( SELECT OutTime, InTime FROM ( SELECT T1.LogoutTime OutTime, MIN(T2.LoginTime) InTime FROM tblLoginLogout AS T1, tblLoginLogout AS T2 WHERE T1.LogoutTime < T2.LoginTime GROUP BY T1.LogoutTime) a WHERE NOT EXISTS ( SELECT 1 FROM tblLoginLogout WHERE LoginTime < InTime AND LogoutTime > OutTime)) lapses ON HStart < InTime AND HEnd > OutTimeGROUP BY HStartORDER BY HStart
Where Numbers is a single-column (N) table of non-negative integers (...hmm, deja vu) with at least as many rows as reporting periods (365*24 = 8760, here).The subquery hours just generates a row for each contiguous period being reported (from @RepStartTime to @RepEndTime in @RepFreq second periods). It should really be called something else. I wouldn't recommend changing @RepFreq to much less than 3600!The subquery lapses find the periods when no operator was logged in. It isn't very efficient, but it should be ok for 8 hour shifts of 3 operators and it will cope with the general case. For each logout time, it finds the next login time and checks there are no (other) operator sessions overlapping that logout-to-login period.The main query just joins each lapse to the hours it occurs in and calculates the period for each lapse that falls within the hour, then groups by hours and adds all the lapses in the hour (this is ok because lapses can't overlap by definition).This was 'tested' (for small values of 'tested') on a table like this:CREATE TABLE tblLoginLogout ( Operator int NOT NULL, LoginTime datetime NOT NULL, LogoutTime datetime NOT NULL)
with test data for 3 operators working 8 hours shifts, logging in and out up to 1/2 hour either side of their nominal time:SET NOCOUNT ONDECLARE @o int, @shiftstart datetimeDECLARE @start datetime, @end datetimeSET @shiftstart = '2001-01-01 00:00:00'WHILE @shiftstart < '2002-01-01 00:00:00'BEGIN SET @o = 0 WHILE @o < 3 BEGIN SET @start = DATEADD(second, FLOOR(RAND() * 3600.0 - 1800.0), @shiftstart) SET @shiftstart = DATEADD(hour, 8, @shiftstart) SET @end = DATEADD(second, FLOOR(RAND() * 3600.0 - 1800.0), @shiftstart) INSERT INTO tblLoginLogout VALUES (@o, @start, @end) SET @o = @o + 1 ENDENDSET NOCOUNT OFF
Edited by - Arnold Fribble on 01/18/2002 04:26:08