假设您有一个泛型分析工具,该工具可以跟踪页面浏览量,并且希望获取每个用户的第一个事件和最后一个事件之间的总时间。可以使用窗口功能吗?
以下是示例数据:
$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');
完成所有操作后,我们的预期结果如下:
平均给我们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”(或类似的列)来帮助查询
答案 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