How can I check for average concurrent events in a SQL table based on the date, time and duration of the events?

后端 未结 6 1050
滥情空心
滥情空心 2021-02-05 22:48

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).

6条回答
  •  醉话见心
    2021-02-05 23:44

    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
    

提交回复
热议问题