MySQL是否可以从时间序列中计算平均时间?

时间:2019-03-04 10:45:01

标签: mysql analytics

假设您有一个泛型分析工具,该工具可以跟踪页面浏览量,并且希望获取每个用户的第一个事件和最后一个事件之间的总时间。可以使用窗口功能吗?

以下是示例数据:

$timeout

这让我们从以下开始:

CREATE TABLE `user_events` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(45) DEFAULT NULL,
  `page` varchar(45) DEFAULT NULL,
  `ts` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO `user_events` VALUES 
  (1,'user1','home','2019-03-03 10:00:00'),
  (2,'user2','home','2019-03-03 10:00:11'),
  (3,'user1','about','2019-03-03 10:00:23'),
  (4,'user1','contact','2019-03-03 10:00:47'),
  (5,'user2','services','2019-03-03 10:01:04'),
  (6,'user2','contact','2019-03-03 10:01:15'),
  (7,'user1','home','2019-03-03 18:20:34'),
  (8,'user1','services','2019-03-03 18:20:37');

完成所有操作后,我们的预期结果如下:

  • user1 = 47秒
  • user2 = 64秒
  • user1会话2 = 3秒

平均给我们38秒

有一个博客似乎以Postgres为例https://blog.jooq.org/2015/05/12/use-this-neat-window-function-trick-to-calculate-time-differences-in-a-time-series/,博客的最后部分提到使用“重置”来启动计时器,但是我仍然无法将Postgres转换为MySQL < / p>

我遵循了https://modern-sql.com/feature/filter

中FILTER的替代方法
mysql> select * from user_events;
+----+-------+----------+---------------------+
| id | user  | page     | ts                  |
+----+-------+----------+---------------------+
|  1 | user1 | home     | 2019-03-03 10:00:00 |
|  2 | user2 | home     | 2019-03-03 10:00:11 |
|  3 | user1 | about    | 2019-03-03 10:00:23 |
|  4 | user1 | contact  | 2019-03-03 10:00:47 |
|  5 | user2 | services | 2019-03-03 10:01:04 |
|  6 | user2 | contact  | 2019-03-03 10:01:15 |
|  7 | user1 | home     | 2019-03-03 18:20:34 |
|  8 | user1 | services | 2019-03-03 18:20:37 |
+----+-------+----------+---------------------+

但是我显然需要某种分组,因此第二个用户的首页访问不会重置第一个。

我还尝试了一个简单的最小/最大

mysql> SELECT
    ->   COUNT(CASE WHEN page = 'home' THEN 1 END)  OVER (ORDER BY ts) c,
    ->   ts
    -> FROM user_events;
+---+---------------------+
| c | ts                  |
+---+---------------------+
| 1 | 2019-03-03 10:00:00 |
| 2 | 2019-03-03 10:00:11 |
| 2 | 2019-03-03 10:00:23 |
| 2 | 2019-03-03 10:00:47 |
| 2 | 2019-03-03 10:01:04 |
| 2 | 2019-03-03 10:01:15 |
| 3 | 2019-03-03 18:20:34 |
| 3 | 2019-03-03 18:20:37 |
+---+---------------------+

但是再次,我需要重设,以便user1的2个会话不会被分组。

我甚至可能尝试处理给定的数据,还是我需要另一个“ session_id”(或类似的列)来帮助查询

1 个答案:

答案 0 :(得分:2)

不幸的是,您已经正确猜到了,您将需要在数据模型中使用session_id字段,以便准确地识别每个用户实际上都是唯一的。解决此问题的唯一方法是设置默认计时器值,如果超过该默认值,该默认值将认为用户已创建了新会话,但这非常麻烦,我不建议这样做,因为它会带来其他问题,并且计算将成倍增加难以处理。

用户1在您的示例中出现了两次,这使得很难从数据模型中获得想要的结果。任何没有此结果的人都会说user1在系统上花费了8小时20分30秒。

如果将session_id插入到user_events表中,则可以实现目标。 然后,您可以通过执行以下查询来找到每个用户会话所花费的时间(以秒为单位)

    SELECT session_id, max(ts) as end_of_session, min(ts) as start_of_session, 
    (UNIX_TIMESTAMP(max(ts)) - UNIX_TIMESTAMP(min(ts))) as delta_ts
    FROM user_events
    GROUP BY session_id
    ORDER BY session_id

然后,您可以将其包装在一个呼叫周围,该呼叫可以通过以下查询得出所有唯一用户会话的平均时长

SELECT avg(delta_ts)
FROM
(    
    SELECT session_id, max(ts) as end_of_session, min(ts) as start_of_session, 
    (UNIX_TIMESTAMP(max(ts)) - UNIX_TIMESTAMP(min(ts))) as delta_ts
    FROM user_events
    GROUP BY session_id
    ORDER BY session_id
)q_inner

如果将session_id字段添加到模型中,此示例将按预期工作。

CREATE TABLE `user_events` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `session_id` varchar(10) NOT NULL,
  `user` varchar(45) DEFAULT NULL,
  `page` varchar(45) DEFAULT NULL,
  `ts` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO `user_events` VALUES 
  (1,'z1a64','user1','home','2019-03-03 10:00:00'),
  (2,'wopa1','user2','home','2019-03-03 10:00:11'),
  (3,'z1a64','user1','about','2019-03-03 10:00:23'),
  (4,'z1a64','user1','contact','2019-03-03 10:00:47'),
  (5,'wopa1','user2','services','2019-03-03 10:01:04'),
  (6,'wopa1','user2','contact','2019-03-03 10:01:15'),
  (7,'n3dhe','user1','home','2019-03-03 18:20:34'),
  (8,'n3dhe','user1','services','2019-03-03 18:20:37');


SELECT avg(delta_ts)
FROM
(    
    SELECT session_id, max(ts) as end_of_session, min(ts) as start_of_session, 
    (UNIX_TIMESTAMP(max(ts)) - UNIX_TIMESTAMP(min(ts))) as delta_ts
    FROM user_events
    GROUP BY session_id
    ORDER BY session_id
)q_inner