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).
I approached the problem by converting the data into an easier format. I created a table where each row represents one minute of a call. Once you have that the average per minute by hour is simple. There are multiple selects in there to show the intermediate results. As long as the time range being queried and the durations aren't extremely large, it should be ok...?
CREATE TABLE #Records(
seconds char(10),
[time] char(4),
date char(8),
dur int,
system int,
port int
)
/*
seconds is an s[time] value. It's the difference of seconds from UTC 1/1/1970 00:00:00 to the current UTC [time], we use it as an identifier (like epoch).
[time] is the [time] the call was made.
date is the day the call was made.
dur is the duration of the call in seconds.
system is the system number.
port is the port on the system (not particularly relevant for this question).
*/
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924228','1923','20090416',105,2,2)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239923455','1910','20090416',884,1,97)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924221','1923','20090416',116,2,15)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924259','1924','20090416',90,1,102)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239923458','1910','20090416',891,2,1)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924255','1924','20090416',99,2,42)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924336','1925','20090416',20,2,58)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924293','1924','20090416',64,2,41)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239923472','1911','20090416',888,2,27)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924347','1925','20090416',25,1,100)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924301','1925','20090416',77,2,55)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924332','1925','20090416',52,2,43)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924240','1924','20090416',151,1,17)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924313','1925','20090416',96,2,62)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924094','1921','20090416',315,2,16)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239923643','1914','20090416',788,2,34)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924447','1927','20090416',6,2,27)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924342','1925','20090416',119,2,15)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924397','1926','20090416',76,2,41)
INSERT INTO #Records(seconds, [time], date, dur, system, port) VALUES('1239924457','1927','20090416',23,2,27)
/* convert date + [time] into datetimes */
select
seconds,
system,
cast(date + ' ' + left([time], 2) + ':' + right([time], 2) as datetime) as start_date,
/* end date to the minute */
dateadd(mi, datediff(mi, 0, dateadd(s, dur, cast(date + ' ' + left([time], 2) + ':' + right([time], 2) as datetime))), 0) as end_date
into
#r
from
#Records
select * from #r order by system, seconds, start_date, end_date;
/* create a row for each minute of each call */
create table #r_min(rnd int, seconds char(10), system int, minute datetime)
declare @maxrnd int;
select @maxrnd = max(datediff(mi, r.start_date, r.end_date)) from #r r
declare @i int;
set @i = 0;
while @i < @maxrnd begin
insert into #r_min
select @i, r.seconds, r.system, dateadd(mi, @i, r.start_date)
from #r r
where dateadd(mi, @i, r.start_date) <= r.end_date
set @i = @i + 1
end
select * from #r_min order by system, seconds, minute
/* concurrent per minute */
select
system, minute, count(*) as cnt
from
#r_min
group by
system, minute
order by
system, minute
/* avg concurrent per minute by hour */
select
m.system,
dateadd(hh, datediff(hh, 0, m.minute), 0) as hour,
avg(m.cnt) as average_concurrent_per_minute
from
(select
system, minute, count(*) as cnt
from
#r_min
group by
system, minute
) m
group by
m.system,
dateadd(hh, datediff(hh, 0, m.minute), 0)
drop table #Records
drop table #r
drop table #r_min
the last select yields...
system hour average_concurrent_per_minute
1 2009-04-16 19:00:00.000 1
2 2009-04-16 19:00:00.000 3