【发布时间】:2009-05-18 09:20:18
【问题描述】:
我有一个存储一些时间戳的 mysql 数据库。让我们假设表中只有 ID 和时间戳。时间戳可能重复。
我想找到不重复的连续行之间的平均时间差(按时间)。有没有办法在 SQL 中做到这一点?
【问题讨论】:
我有一个存储一些时间戳的 mysql 数据库。让我们假设表中只有 ID 和时间戳。时间戳可能重复。
我想找到不重复的连续行之间的平均时间差(按时间)。有没有办法在 SQL 中做到这一点?
【问题讨论】:
如果你的表是 t,而你的时间戳列是 ts,而你想要以秒为单位的答案:
SELECT TIMESTAMPDIFF(SECOND, MIN(ts), MAX(ts) )
/
(COUNT(DISTINCT(ts)) -1)
FROM t
这对于大型表来说会快几英里,因为它没有 n-squared JOIN
这使用了一个可爱的数学技巧来帮助解决这个问题。暂时忽略重复的问题。连续行的平均时间差是第一个时间戳和最后一个时间戳的差除以行数-1。
证明:连续行之间的平均距离是连续行之间的距离之和,除以连续行数。但是连续行之间的差异之和只是第一行和最后一行之间的距离(假设它们是按时间戳排序的)。而连续行数为总行数-1。
然后我们只需将时间戳设置为不同的条件。
【讨论】:
ID 是连续的吗?
你可以这样做,
SELECT
a.ID
, b.ID
, a.Timestamp
, b.Timestamp
, b.timestamp - a.timestamp as Difference
FROM
MyTable a
JOIN MyTable b
ON a.ID = b.ID + 1 AND a.Timestamp <> b.Timestamp
这将为您提供每个连续行对的时间差列表...
然后您可以将其包装在 AVG 分组中...
【讨论】:
这是一种方法:
select avg(timestampdiff(MINUTE,prev.datecol,cur.datecol))
from table cur
inner join table prev
on cur.id = prev.id + 1
and cur.datecol <> prev.datecol
timestampdiff 函数允许您在天、月、秒等之间进行选择。
如果id不连续,可以通过添加一条中间没有其他行的规则来选择上一行:
select avg(timestampdiff(MINUTE,prev.datecol,cur.datecol))
from table cur
inner join table prev
on prev.datecol < cur.datecol
and not exists (
select *
from table inbetween
where prev.datecol < inbetween.datecol
and inbetween.datecol < cur.datecol)
)
【讨论】:
根据本次讨论适用于 SQL Server。
使用的基本列是: cmis_load_date:与每条记录关联的日期/时间戳。 extract_file:加载记录的文件的完整路径。
评论: 每个文件中可以有许多记录。记录必须按 extract_file 列上加载的文件进行分组。在一个文件和下一个文件加载之间可能会经过几天的间隔。任何列中都没有可靠的顺序值,因此分组的行按每个文件组中的最小加载日期排序,然后 ROW_NUMBER() 函数用作临时顺序值。
SELECT
AVG(DATEDIFF(day, t2.MinCMISLoadDate, t1.MinCMISLoadDate)) as ElapsedAvg
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY MIN(cmis_load_date)) as RowNumber,
MIN(cmis_load_date) as MinCMISLoadDate,
CASE WHEN NOT CHARINDEX('\', extract_file) > 0 THEN '' ELSE RIGHT(extract_file, CHARINDEX('\', REVERSE(extract_file)) - 1) END as ExtractFile
FROM
TrafTabRecordsHistory
WHERE
court_id = 17
and
cmis_load_date >= '2019-09-01'
GROUP BY
CASE WHEN NOT CHARINDEX('\', extract_file) > 0 THEN '' ELSE RIGHT(extract_file, CHARINDEX('\', REVERSE(extract_file)) - 1) END
) t1
LEFT JOIN
(
SELECT
ROW_NUMBER() OVER (ORDER BY MIN(cmis_load_date)) as RowNumber,
MIN(cmis_load_date) as MinCMISLoadDate,
CASE WHEN NOT CHARINDEX('\', extract_file) > 0 THEN '' ELSE RIGHT(extract_file, CHARINDEX('\', REVERSE(extract_file)) - 1) END as ExtractFile
FROM
TrafTabRecordsHistory
WHERE
court_id = 17
and
cmis_load_date >= '2019-09-01'
GROUP BY
CASE WHEN NOT CHARINDEX('\', extract_file) > 0 THEN '' ELSE RIGHT(extract_file, CHARINDEX('\', REVERSE(extract_file)) - 1) END
) t2 on t2.RowNumber + 1 = t1.RowNumber
【讨论】:
旧帖子,但是....
简单的方法是使用 Lag 函数和 TIMESTAMPDIFF
SELECT
id,
TIMESTAMPDIFF('MINUTES', PREVIOUS_TIMESTAMP, TIMESTAMP) AS TIME_DIFF_IN_MINUTES
FROM (
SELECT
id,
TIMESTAMP,
LAG(TIMESTAMP, 1) OVER (ORDER BY TIMESTAMP) AS PREVIOUS_TIMESTAMP
FROM TABLE_NAME
)
【讨论】: