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