【问题标题】:How to find the average time difference between rows in a table?如何找到表中行之间的平均时间差?
【发布时间】:2009-05-18 09:20:18
【问题描述】:

我有一个存储一些时间戳的 mysql 数据库。让我们假设表中只有 ID 和时间戳。时间戳可能重复。

我想找到不重复的连续行之间的平均时间差(按时间)。有没有办法在 SQL 中做到这一点?

【问题讨论】:

    标签: sql mysql


    【解决方案1】:

    如果你的表是 t,而你的时间戳列是 ts,而你想要以秒为单位的答案:

    SELECT TIMESTAMPDIFF(SECOND, MIN(ts), MAX(ts) ) 
           /
           (COUNT(DISTINCT(ts)) -1) 
    FROM t
    

    这对于大型表来说会快几英里,因为它没有 n-squared JOIN

    这使用了一个可爱的数学技巧来帮助解决这个问题。暂时忽略重复的问题。连续行的平均时间差是第一个时间戳和最后一个时间戳的差除以行数-1。

    证明:连续行之间的平均距离是连续行之间的距离之和,除以连续行数。但是连续行之间的差异之和只是第一行和最后一行之间的距离(假设它们是按时间戳排序的)。而连续行数为总行数-1。

    然后我们只需将时间戳设置为不同的条件。

    【讨论】:

    • 太棒了。解决可能的时间戳重复问题的绝佳答案。
    【解决方案2】:

    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 分组中...

    【讨论】:

    • 好的,但是如果 id 是连续的,这将起作用。实际上,我猜 Nick 的答案更好。
    【解决方案3】:

    这是一种方法:

    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)
        )
    

    【讨论】:

      【解决方案4】:

      根据本次讨论适用于 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
      

      【讨论】:

        【解决方案5】:

        旧帖子,但是....

        简单的方法是使用 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
        )
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-07-06
          • 1970-01-01
          • 2022-10-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多