在MySQL中查找时间序列数据间隙的方法?

The*_*Dog 8 mysql database time

假设我们有一个包含两列的数据库表,entry_time和value.entry_time是时间戳,而value可以是任何其他数据类型.记录相对一致,以大约x分钟的间隔输入.然而,在许多时间内,可能不会进行输入,从而在数据中产生"间隙".

在效率方面,通过查询找到至少时间Y(新旧)的最佳方法是什么?

O. *_*nes 20

首先,让我们在表格中按小时汇总条目数.

SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
       COUNT(*) samplecount
  FROM table
 GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
Run Code Online (Sandbox Code Playgroud)

现在,如果您每六分钟(每小时十次)记录一些内容,那么所有samplecount值都应为十.这个表达式:CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)看起来很毛茸茸,但它只是将你的时间戳截断到它们出现的小时,将分钟和分钟归零.

这是相当有效的,并将帮助您入门.如果您可以在entry_time列上添加索引并将查询限制为昨天的样本(如此处所示),则效率非常高.

SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
       COUNT(*) samplecount
  FROM table
 WHERE entry_time >= CURRENT_DATE - INTERVAL 1 DAY
   AND entry_time < CURRENT_DATE
 GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
Run Code Online (Sandbox Code Playgroud)

但是,在检测缺少样品的整个小时时,它并不是很好.它对采样中的抖动也有点敏感.也就是说,如果您的最高时间样本有时是早期的半秒(10:59:30),有时是半秒(11:00:30),那么您的每小时摘要计数将会被取消.所以,这个小时的摘要(或者日摘要,或者摘要等)不是防弹的.

您需要一个自我连接查询才能完全正确地获取内容; 它更像是一个毛球而且效率不高.

让我们首先创建一个带有编号样本的虚拟表(子查询).(这是MySQL的痛苦;其他一些昂贵的DBMS使它变得更容易.无论如何.)

  SELECT @sample:=@sample+1 AS entry_num, c.entry_time, c.value
    FROM (
        SELECT entry_time, value
      FROM table
         ORDER BY entry_time
    ) C,
    (SELECT @sample:=0) s
Run Code Online (Sandbox Code Playgroud)

这个小虚拟表给出了entry_num,entry_time,value.

下一步,我们加入它自己.

SELECT one.entry_num, one.entry_time, one.value, 
       TIMEDIFF(two.value, one.value) interval
  FROM (
     /* virtual table */
  ) ONE
  JOIN (
     /* same virtual table */
  ) TWO ON (TWO.entry_num - 1 = ONE.entry_num)
Run Code Online (Sandbox Code Playgroud)

这将表格排列下来两个相互偏移的单个条目,由JOIN的ON子句控制.

最后,我们选择此表中的值interval大于您的阈值,并且样本的时间恰好在丢失的值之前.

全部自连接查询就是这个.我告诉过你这是一个毛球.

SELECT one.entry_num, one.entry_time, one.value, 
       TIMEDIFF(two.value, one.value) interval
  FROM (
    SELECT @sample:=@sample+1 AS entry_num, c.entry_time, c.value
      FROM (
          SELECT entry_time, value
            FROM table
           ORDER BY entry_time
      ) C,
      (SELECT @sample:=0) s
  ) ONE
  JOIN (
    SELECT @sample2:=@sample2+1 AS entry_num, c.entry_time, c.value
      FROM (
          SELECT entry_time, value
            FROM table
           ORDER BY entry_time
      ) C,
      (SELECT @sample2:=0) s
  ) TWO ON (TWO.entry_num - 1 = ONE.entry_num)
Run Code Online (Sandbox Code Playgroud)

如果必须在大型表的生产中执行此操作,则可能需要为数据的子集执行此操作.例如,您可以每天对前两天的样本进行此操作.这将是相当有效的,并且还将确保您在午夜时不会忽略任何遗失的样本.要做到这一点,你的小小的rownumbered虚拟表将是这样的.

  SELECT @sample:=@sample+1 AS entry_num, c.entry_time, c.value
    FROM (
        SELECT entry_time, value
      FROM table
         ORDER BY entry_time
         WHERE entry_time >= CURRENT_DATE - INTERVAL 2 DAY
           AND entry_time < CURRENT_DATE /*yesterday but not today*/
    ) C,
    (SELECT @sample:=0) s
Run Code Online (Sandbox Code Playgroud)