views:

275

answers:

3

I would like to take the average of the time difference from Table1 below. The values are not consecutive and occasionally the time value is repeated, so I need to 1) sort by time, 2) discard non-unique values, 3) perform the time difference (in milliseconds), then 4) average the resulting time difference values. Further I'd like to 5) limit the datediff operation to a chosen time range, such as WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= _TimeStamp >= '20091220 11:59:56.8'. I am pretty stumped how to put this all together!

Table1:
_TimeStamp
2009-12-20 11:59:56.0
2009-12-20 11:59:56.5
2009-12-20 11:59:56.3
2009-12-20 11:59:56.4
2009-12-20 11:59:56.4
2009-12-20 11:59:56.9

+1  A: 

Step 1 is to select only unique times:

SELECT DISTINCT _TimeStamp FROM table 
    WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8';

Then, if you want to, say, compare all times with each other (not sure how you want to select times), you could do something crazy like:

SELECT t1._TimeStamp, t2._TimeStamp, DATEDIFF(ms,t1._TimeStamp,t2._TimeStamp) FROM 
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t1 
    INNER JOIN
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t2
WHERE t1._TimeStamp != t2._TimeStamp;

My syntax might be off, because I'm coming from MySQL, but something similar should work.

If you want the average, you could try taking the average of the above results:

SELECT AVG(DATEDIFF(ms,t1._TimeStamp,t2._TimeStamp)) FROM 
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t1 
    INNER JOIN
    (SELECT DISTINCT _TimeStamp FROM table 
        WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8') AS t2
WHERE t1._TimeStamp != t2._TimeStamp;

Still untested, but in theory, I think it should work.

cmptrgeekken
`ss` is seconds, not milliseconds (`ms`)
OMG Ponies
I messed up my variable selection in the outer query. I used `t1` instead of `t1._TimeStamp`. Maybe that was the issue.
cmptrgeekken
Thanks for all your help. As you can tell joins are new to me so I appreciate it.
KE
A: 

If my assumptions on what you want are correct, then I see two ways of doing it.

The direct way:

SELECT
    AVG(DATEDIFF(ms, T1.my_time, T2.my_time))
FROM
    My_Table T1
INNER JOIN My_Table T2 ON
    T2.my_time > T1.my_time
WHERE
    NOT EXISTS
    (
        SELECT
            *
        FROM
            My_Table T3
        WHERE
            (T3.my_time > T1.my_time AND T3.my_time < T2.my_time) OR
            (T3.my_time = T1.my_time AND T3.my_pk < T1.my_pk) OR
            (T3.my_time = T2.my_time AND T3.my_pk < T2.my_pk)
    )

The tricky way:

SELECT
    DATEDIFF(ms, MIN(my_time), MAX(my_time))/(COUNT(DISTINCT my_time) - 1)
FROM
    My_Table

After all, the average differences is just the total difference divided by the number of divisions into which you're breaking it down.

You'll need to add WHERE clauses for the date range if you want to limit by that and you will need to account for the possibility of divide by zero in the second query.

Tom H.
A: 

Here's one that works and is not ugly:

;WITH Time_CTE AS
(
    SELECT
        MIN(_Timestamp) AS dt,
        ROW_NUMBER() OVER (ORDER BY MIN(_Timestamp)) AS RowNum
    FROM Table1
    GROUP BY _Timestamp
)
SELECT
    t1.dt AS StartDate,
    t2.dt AS EndDate,
    DATEDIFF(MS, t1.dt, t2.dt) AS Elapsed
FROM Time_CTE t1
INNER JOIN Time_CTE t2
ON t2.RowNum = t1.RowNum + 1

Will give you the following output from your example:

StartDate               | EndDate                 | Elapsed
------------------------+-------------------------+--------
2009-12-20 11:59:56.000 | 2009-12-20 11:59:56.300 | 300
2009-12-20 11:59:56.300 | 2009-12-20 11:59:56.400 | 100
2009-12-20 11:59:56.400 | 2009-12-20 11:59:56.500 | 100
2009-12-20 11:59:56.500 | 2009-12-20 11:59:56.900 | 400

Edit: If you want to restrict time ranges then just add WHERE _Timestamp BETWEEN @StartDate AND @EndDate before the GROUP BY line.

Edit2: And if you want the average, then change that final SELECT t1.dt, ... statement to:

SELECT AVG(DATEDIFF(MS, t1.dt, t2.dt))
FROM Time_CTE t1 ... (same as above)
Aaronaught
Thanks, that worked! I appreciate everyone's help...I learned many new (to me) SQL concepts. Never would have gotten there on my own.
KE