Datediff entre filas no consecutivas en una mesa
-
19-09-2019 - |
Pregunta
Me gustaría tomar el promedio de la diferencia de tiempo de la Tabla1 a continuación. Los valores no son consecutivas y, ocasionalmente, se repite el valor de tiempo, por lo que necesitan para 1) ordenar por tiempo, 2) descartar valores no únicos, 3) realizar la diferencia de tiempo (en milisegundos), entonces 4) Medida de la diferencia de tiempo resultante valores. Además me gustaría 5) limitar la operación datediff a un intervalo de tiempo elegido, tal como DONDE _TimeStamp> = '20091220 11: 59: 56.1' Y _TimeStamp <= _TimeStamp> = '20091220 11: 59: 56.8'. Estoy bastante perplejo cómo poner todo esto junto!
Tabla 1:
_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
Solución
Aquí hay una que funciona y no es fea:
;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
Le dará la siguiente salida de su ejemplo:
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
Editar:. Si desea restringir los rangos de tiempo a continuación, sólo tiene que añadir WHERE _Timestamp BETWEEN @StartDate AND @EndDate
antes de la línea GROUP BY
Edit2: Y si desea que el promedio, a continuación, cambiar esa declaración SELECT t1.dt, ...
final a:
SELECT AVG(DATEDIFF(MS, t1.dt, t2.dt))
FROM Time_CTE t1 ... (same as above)
Otros consejos
Paso 1 es seleccionar veces solamente únicos:
SELECT DISTINCT _TimeStamp FROM table
WHERE _TimeStamp >= '20091220 11:59:56.1' AND _TimeStamp <= '20091220 11:59:56.8';
Entonces, si usted quiere, por ejemplo, comparar todo momento entre sí (no sé cómo desea seleccionar veces), se puede hacer algo loco como:
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;
Mi sintaxis podría ser apagado, porque estoy viniendo de MySQL, pero algo similar debería funcionar.
Si desea que el promedio, podría intentar tomar el promedio de los resultados anteriores:
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;
Aún no probado, pero en teoría, creo que debería funcionar.
Si mis suposiciones sobre lo que quiere son correctas, entonces veo dos formas de hacerlo.
La forma más directa:
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)
)
La forma más complicado:
SELECT
DATEDIFF(ms, MIN(my_time), MAX(my_time))/(COUNT(DISTINCT my_time) - 1)
FROM
My_Table
Después de todo, las diferencias promedio es sólo la diferencia total dividido por el número de divisiones en el que se está rompiendo abajo.
Se tendrá que añadir cláusulas donde durante el intervalo de fechas si desea limitar por eso y que tendrá que tener en cuenta la posibilidad de dividir por cero en la segunda consulta.