代码之家  ›  专栏  ›  技术社区  ›  hallo02

MySQL时序操作

  •  1
  • hallo02  · 技术社区  · 8 年前

    我在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 回复  |  直到 8 年前
        1
  •  1
  •   Nick SamSmith1986    8 年前

    我认为在MySQL5.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
    
        2
  •  0
  •   hallo02    8 年前

    尽管@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 "" 
    

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