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

后端 未结 6 1049
滥情空心
滥情空心 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:23

    My first bit of advice would be, if you ever find yourself saying (when using SQL) "I can create a loop..." then you should immediately start looking for a set-based approach. Get out of the procedural mindset when using SQL.

    There are still a few fuzzy parts to your logic. Does a call count as being during a minute period if it simply has any portion of the call during that minute? For example, if a call starts at 1923 and lasts 62 seconds is it considered to overlap with all calls starting at 1924? I'm going to assume yes on that one, but you can adjust the code below if that's not true. It should be a minor tweak.

    For the breakdown to minutes I would usually use a table with time spans - a start time and end time for each of the slices in which I'm interested. In your case since you are dealing with exact minutes and your start times are in minutes (even if the data type is screwed up) I'm just going to use a single column with the exact minute in question.

    To set up that table:

    CREATE TABLE dbo.Minutes (
        start_time  INT NOT NULL,
        CONSTRAINT PK_Minutes PRIMARY KEY CLUSTERED (start_time)
    )
    
    DECLARE
        @hour   TINYINT,
        @minute TINYINT
    
    SET @hour = 19
    SET @minute = 0
    
    WHILE (@hour <= 20)
    BEGIN
        INSERT INTO dbo.Minutes (start_time) VALUES (@hour * 100 + @minute)
    
        SET @minute = @minute + 1
        IF @minute = 60
        BEGIN
            SET @minute = 0
            SET @hour = @hour + 1
        END
    END
    

    Now we can select for the averages, etc.

    SELECT
        M.start_time,
        COUNT(R.seconds)
    FROM
        dbo.Minutes M
    LEFT OUTER JOIN dbo.Records R ON
        M.start_time BETWEEN CAST(R.time AS INT) AND
            (CAST(SUBSTRING(time, 1, 2) AS INT) * 100) +    -- hours
            (FLOOR((CAST(SUBSTRING(time, 3, 2) AS INT) + FLOOR(dur/60))/60)) +  -- carryover to hours
            (CAST(SUBSTRING(time, 3, 2) AS INT) + dur/60) % 60  -- minutes
    GROUP BY
        M.start_time
    

    You'll need to either use that as a subquery to get the averages over a given time. Since it's late on Friday I'll leave that step up to you ;)

    EDIT: One last caveat: I didn't account for time spans that cross day boundaries (i.e., go past midnight). Hopefully the code points you in the right direction for that. A better approach might be to create a view that turns all of those nasty strings into actual DATETIME values, then this becomes really trivial with the Minutes table.

提交回复
热议问题