I have a set of call detail records, and from those records, I\'m supposed to determine the average concurrent active calls per system, per hour (at a precision of one minute).
As MarkusQ stated, your definition of "concurrent" allows you to short cut the maths.
The average concurrent calls is then (1+2+1)/intervalCount
The (1+2+1) can be calculated differently, and more quickly/easily:
The important fact here (and why I bothered reply after MarkusQ posted) is that the duration of a call itself isn't enough to calculate how many minute intervals are covered. In my example, both calls only last 2 seconds...
You need the following info:
- the "start time", rounded down to the minute
- the "end time", rounded down to the minute
=> covered intervals = number of minutes difference + 1
To round the "time" field down to the minute I'd use this...
DATEADD(minute, DATEDIFF(minute, 0, time), 0)
So the number of covered minutes by a single call would be...
DATEDIFF(
minute,
DATEADD(minute, DATEDIFF(minute, 0, time), 0),
DATEADD(second, dur, time)
) + 1
No need to round the "end time" down.
Using DATEDIFF(minute) gives rounding down anyway.
SUM that value for the range you're looking at, then divde by the number of minutes in that range, and you have your answer.
If you're only looking for calls that are truely concurrent you can't use such tricks, but it's still possible (I've had to do something similar). But for your definition of concurrent, this should do it...
DECLARE
@date DATETIME, @start DATETIME, @end DATETIME
SELECT
@date = '2009 Jan 01', @start = '12:00', @end = '13:00'
SELECT
system,
SUM(
DATEDIFF(
minute,
CASE WHEN
CAST(LEFT(time,2) + ':' + RIGHT(time,2) AS DATETIME) < @start
THEN
@start
ELSE
CAST(LEFT(time,2) + ':' + RIGHT(time,2) AS DATETIME)
END,
CASE WHEN
DATEADD(second, dur, CAST(LEFT(time,2) + ':' + RIGHT(time,2) AS DATETIME)) > @end
THEN
@end
ELSE
DATEADD(second, dur, CAST(LEFT(time,2) + ':' + RIGHT(time,2) AS DATETIME))
END
) + 1
)
/
CAST(DATEDIFF(minute, @start, @end) AS FLOAT)
FROM
records
WHERE
date = @date
AND CAST(LEFT(time,2) + ':' + RIGHT(time,2) AS DATETIME) >= @start
AND DATEADD(second, dur, CAST(LEFT(time,2) + ':' + RIGHT(time,2) AS DATETIME)) < @end
GROUP BY
system
This will deliberately not include the interval 13:00->13:01
Only the 60 "1 minute long intervals" 12:00->12:01 through to 12:59->13:00
EDIT:
I just noticed that your times and dates are stored as strings, you'd need to convert those to DATETIMEs for my code to work.
EDIT2:
Bug corrected. If a call started at "11:59:01" and ended at "12:00:01", the "11:59" interval should not be counted. CASE statements added to compensate.
Various Layout Edits