Kyle Brandt
Kyle Brandt

Reputation: 28387

TSQL Rolling Average of Time Groupings

This is a follow up to: TSQL Group by N Seconds . (I got what I asked for, but didn't ask for the right thing)

How can I get a rolling average of 1 second groups of count(*)?

So I want to return per second counts, but I also want to be able to smooth that out over certain intervals, say 10 seconds.

So one method might be to take the average per second of every 10 seconds, can that be done in TSQL?

Ideally, the time field would be returned in Unix Time.

Upvotes: 2

Views: 729

Answers (1)

Quassnoi
Quassnoi

Reputation: 425341

SQL Server is not particularly good in rolling/cumulative queries.

You can use this:

WITH    q (unix_ts, cnt) AS
        (
        SELECT  DATEDIFF(s, '1970-01-01', ts), COUNT(*)
        FROM    record 
        GROUP BY
                DATEDIFF(s, '1970-01-01', ts)
        )
SELECT  *
FROM    q q1
CROSS APPLY
        (
        SELECT  AVG(cnt) AS smooth_cnt
        FROM    q q2
        WHERE   q2.unix_ts BETWEEN q1.unix_ts - 5 AND q1.unix_ts + 5
        ) q2

, however, this may not be very efficient, since it will count the same overlapping intervals over an over again.

For the larger invervals, it may be even better to use a CURSOR-based solution that would allow to keep intermediate results (though normally they are worse performance-wise than pure set-based solutions).

Oracle and PostgreSQL support this clause:

WITH    q (unix_ts, cnt) AS
        (
        SELECT  TRUNC(ts, 'ss'), COUNT(*)
        FROM    record 
        GROUP BY
               TRUNC(ts, 'ss')
        )
SELECT  q.*,
        AVG(cnt) OVER (ORDER BY unix_ts RANGE BETWEEN INTERVAL '-5' SECOND AND INTERVAL '5' SECOND)
FROM    q

which keeps an internal window buffer and is very efficient.

SQL Server, unfortunately, does not support moving windows.

Upvotes: 3

Related Questions