MySQL时间序列操作

时间:2018-05-22 08:32:21

标签: mysql time-series

我在5.6版本中使用MySQL。 (提及因为不存在可用的mysql函数)

给出一个表"运动检测"时间戳。每行检测到一个动作。没有动议意味着没有进入。

Id | Date Time
---------------
1  | 2018-01-01 15:00:01  // Start of activity phase 1
2  | 2018-01-01 15:00:03
3  | 2018-01-01 15:00:06  // Stop of activity phase 1
// Non-Activity phase
4  | 2018-01-01 17:01:06  // Start of activity phase 2
5  | 2018-01-01 17:02:06
6  | 2018-01-01 17:02:09  // Stop of activity phase 2
// Non-Activity phase, big one because of holiday
7  | 2018-01-10 19:40:06  // Start of activity phase 3
8  | 2018-01-10 19:41:06  // Stop of activity phase 3

我很难找到一个SQL查询来概述" 活动阶段"。

我试图得到的是:

Id | Activity starts     | Activity ends
---------------------------------------------
1  | 2018-01-01 15:00:01 | 2018-01-01 15:00:06
2  | 2018-01-01 17:01:06 | 2018-01-01 17:02:09
3  | 2018-01-10 19:40:06 | 2018-01-10 19:41:06

我希望看到" 活动阶段"的开始和结束时间戳。 定义" 活动阶段":" 活动阶段"位于两个" 非活动阶段" (例如)至少30分钟。

提前谢谢你。

2 个答案:

答案 0 :(得分:1)

我认为在MySQL 5.6中实现这一目标的唯一方法是使用存储过程(尽管我很乐意看到有人证明我错了)。这个会做你想要的。请注意,它返回了许多单行结果集,因此您需要在应用程序框架中处理它。或者,您可以修改过程以将中间结果存储到临时表中,然后在过程结束时修改临时表中的SELECT所有内容(参见下文)。

DELIMITER //
DROP PROCEDURE IF EXISTS get_activity //
CREATE PROCEDURE get_activity()
BEGIN
  DECLARE start, thistime, lasttime DATETIME;
  DECLARE activity_count INT DEFAULT 1;
  DECLARE finished INT DEFAULT 0;
  DECLARE activity_cursor CURSOR FOR SELECT atime FROM activity;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
  OPEN activity_cursor;
  FETCH activity_cursor INTO start;
  SET lasttime = start;
  act_loop: LOOP
    FETCH activity_cursor INTO thistime;
    IF finished = 1 THEN
      SELECT activity_count, start, lasttime AS end;
      LEAVE act_loop;
    END IF;
    IF thistime > lasttime + INTERVAL 30 MINUTE THEN
      SELECT activity_count, start, lasttime AS end;
      SET start = thistime;
      SET activity_count = activity_count + 1;
    END IF;
    SET lasttime = thistime;
  END LOOP;
END //

对于您的样本数据,此过程返回:

activity_count  start                   end     
1               2018-01-01 15:00:01     2018-01-01 15:00:06
activity_count  start                   end     
2               2018-01-01 17:01:06     2018-01-01 17:02:09
activity_count  start                   end     
3               2018-01-10 19:40:06     2018-01-10 19:41:06

这是临时表的过程:

DELIMITER //
DROP PROCEDURE IF EXISTS get_activity //
CREATE PROCEDURE get_activity()
BEGIN
  DECLARE start, thistime, lasttime DATETIME;
  DECLARE activity_count INT DEFAULT 1;
  DECLARE finished INT DEFAULT 0;
  DECLARE activity_cursor CURSOR FOR SELECT atime FROM activity;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
  CREATE TEMPORARY TABLE activity_temp (id INT, start DATETIME, end DATETIME);
  OPEN activity_cursor;
  FETCH activity_cursor INTO start;
  SET lasttime = start;
  act_loop: LOOP
    FETCH activity_cursor INTO thistime;
    IF finished = 1 THEN
      INSERT INTO activity_temp VALUES (activity_count, start, lasttime);
      LEAVE act_loop;
    END IF;
    IF thistime > lasttime + INTERVAL 30 MINUTE THEN
      INSERT INTO activity_temp VALUES (activity_count, start, lasttime);
      SET start = thistime;
      SET activity_count = activity_count + 1;
    END IF;
    SET lasttime = thistime;
  END LOOP;
  SELECT * FROM activity_temp;
  DROP TABLE activity_temp;
END //

输出(来自CALL get_activity()):

id  start                   end     
1   2018-01-01 15:00:01     2018-01-01 15:00:06
2   2018-01-01 17:01:06     2018-01-01 17:02:09
3   2018-01-10 19:40:06     2018-01-10 19:41:06

答案 1 :(得分:0)

尽管@Nick提供了合适的答案,但我花了几个小时才找到以下解决方案:

SET @row_number = 0;
SET @row_number2 = 0;
SET @gap_time = "00:30:00";
Select
  "",
  DAYNAME(prep1.datetime2) "Weekday",
  prep1.datetime2 "Activity starts",
  prep2.datetime1 "Activity ends"

FROM

(SELECT
 (@row_number:=@row_number + 1) AS num
 ,detection1.id id1
 ,detection1.insert_datetime datetime1
 ,detection2.id id2
 ,detection2.insert_datetime datetime2
 ,timediff(detection2.insert_datetime,detection1.insert_datetime) as diff
FROM
 MOVEMENT_TRACKING detection1,
 MOVEMENT_TRACKING detection2
WHERE
 detection1.id + 1 = detection2.id
 and timediff(detection2.insert_datetime,detection1.insert_datetime)  > @gap_time
order by detection1.id) as prep1,

(SELECT
 (@row_number2:=@row_number2 + 1) AS num
 ,detection1.id id1
 ,detection1.insert_datetime datetime1
 ,detection2.id id2
 ,detection2.insert_datetime datetime2
 ,timediff(detection2.insert_datetime,detection1.insert_datetime) as diff
FROM
 MOVEMENT_TRACKING detection1,
 MOVEMENT_TRACKING detection2
WHERE
 detection1.id + 1 = detection2.id
 and timediff(detection2.insert_datetime,detection1.insert_datetime)  > @gap_time
order by detection1.id) as prep2

WHERE
 prep1.num + 1 = prep2.num
ORDER BY
 prep1.datetime2 DESC

仍然可以进行一些减少,因为调试原因我让它们进入。有些黑客需要像

一样
Select "" 

因为数据库托管安全警察规则。