【问题标题】:Grouping timestamps by interval between timestamps, then calculating from group MySQL按时间戳之间的间隔对时间戳进行分组,然后从 MySQL 组中计算
【发布时间】:2012-06-29 03:54:34
【问题描述】:

为了把这个问题放到上下文中,我试图根据事件日志计算“应用程序中的时间”。

假设如下表:

user_id   event_time
2         2012-05-09 07:03:38
3         2012-05-09 07:03:42
4         2012-05-09 07:03:43
2         2012-05-09 07:03:44
2         2012-05-09 07:03:45
4         2012-05-09 07:03:52
2         2012-05-09 07:06:30

我想从彼此相距 2 分钟内(并按用户分组)的一组时间戳中获取最高和最低 event_time 之间的差异。如果时间戳超出该集合的 2 分钟间隔,则应将其视为另一个集合的一部分。

期望的输出:

user_id  seconds_interval
2        7     (because 07:03:45 - 07:03:38 is 7 seconds)
3        0     (because 07:03:42)
4        9     (because 07:03:52 - 2012-05-09 07:03:43)
2        0     (because 07:06:30 is outside 2 min interval of 1st user_id=2 set)

这是我尝试过的,虽然我无法在seconds_interval 上分组(即使可以,我也不确定这是正确的方向):

SELECT (max(tr.event_time)-min(tr.event_time)) as seconds_interval
FROM some_table tr
INNER JOIN TrackingRaw tr2 ON (tr.event_time BETWEEN 
   tr2.event_time - INTERVAL 2 MINUTE AND tr2.event_time + INTERVAL 2 MINUTE) 
GROUP BY seconds_interval

【问题讨论】:

    标签: mysql timestamp


    【解决方案1】:

    我认为没有一种非常直接的方法可以查询您现有的表来生成您想要的数据。但是,您可以维护第二个用户会话表(当然,这样做的缺点是,如果您以后想要使用不同会话超时期限的报告,则需要从头开始重新填充该表):

    CREATE TABLE Sessions (
      user_id INT,
      session_start TIMESTAMP,
      session_end   TIMESTAMP,
      PRIMARY KEY (user_id, session_start),
      FOREIGN KEY (user_id, session_start) REFERENCES TrackingRaw(user_id, event_time),
      FOREIGN KEY (user_id, session_end  ) REFERENCES TrackingRaw(user_id, event_time)
    );
    

    您可以使用使用INSERT ... SELECT ... ON DUPLICATE KEY UPDATE 的触发器自动填充/更新此类表:

    CREATE TRIGGER after_insert_TrackingRaw AFTER INSERT ON TrackingRaw FOR EACH ROW
      INSERT INTO Sessions (user_id, session_start, session_end)
        SELECT NEW.user_id,
               IFNULL(MAX(session_start), NEW.event_time),
               NEW.event_time
        FROM   Sessions
        WHERE  user_id = NEW.user_id
           AND session_end >= NEW.event_time - INTERVAL 2 MINUTE
      ON DUPLICATE KEY UPDATE
        session_start = session_start,
        session_end   = NEW.event_time;
    

    然后,获取你想要的查询结果:

    SELECT user_id, session_end - session_start AS seconds_interval FROM Sessions;
    

    sqlfiddle 上查看。


    更新

    经过进一步思考,您当然可以在存储过程中构建这样一个Sessions 表:

    CREATE PROCEDURE getSessions(IN secs INT) READS SQL DATA BEGIN
      DECLARE no_more_rows BOOLEAN;
      DECLARE cur CURSOR FOR
        SELECT user_id, event_time FROM TrackingRaw ORDER BY event_time ASC;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
    
      DROP   TEMPORARY TABLE IF EXISTS Sessions;
      CREATE TEMPORARY TABLE Sessions (
        user_id INT,
        session_start TIMESTAMP,
        session_end   TIMESTAMP,
        PRIMARY KEY(user_id,session_start),
        FOREIGN KEY(user_id,session_start) REFERENCES TrackingRaw(user_id,event_time),
        FOREIGN KEY(user_id,session_end  ) REFERENCES TrackingRaw(user_id,event_time)
      );
    
      OPEN cur;
      the_loop: LOOP
        FETCH cur INTO @u, @t;
        IF no_more_rows THEN
          CLOSE cur;
          LEAVE the_loop;
        END IF;
    
        INSERT INTO Sessions
          SELECT @u, IFNULL(MAX(session_start), @t), @t
          FROM   Sessions
          WHERE  user_id = @u AND session_end >= @t - secs
        ON DUPLICATE KEY UPDATE
          session_start = session_start, session_end = @t
      END LOOP the_loop;
    
      DEALLOCATE PREPARE stmt;
      SELECT user_id, session_end - session_start AS seconds_interval FROM Sessions;
      DROP TEMPORARY TABLE Sessions;
    END;;
    

    然后获取你的输出:

    CALL getSessions(120); -- for a 2 minute (120 second) timeout
    

    【讨论】:

      猜你喜欢
      • 2015-03-07
      • 1970-01-01
      • 2016-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      相关资源
      最近更新 更多