Возможно ли для MySQL вычислить среднее время из временного ряда? - PullRequest
0 голосов
/ 04 марта 2019

Допустим, у вас есть универсальный аналитический инструмент, который отслеживает просмотры страниц и вы хотите получить общее время между первым и последним событием каждого пользователя.Возможно ли это с помощью оконной функции?

Вот пример данных:

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');

Что дает нам начать это с:

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 |
+----+-------+----------+---------------------+

Наши ожидаемые результаты послевсе это делается следующим образом:

  • user1 = 47 секунд
  • user2 = 64 секунды
  • user1 session2 = 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

. Я выбрал альтернативу FILTER из https://modern -sql.com / feature / filter

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 |
+---+---------------------+

Но мне, очевидно, нужна какая-то группировка, чтобы при посещении домашней страницы 2-го пользователя не сбрасывалось первое.

Я также пробовал просто min / max

mysql> select TIMEDIFF(max(ts),min(ts)) as session_length, user
    -> from user_events
    -> group by user;
+----------------+-------+
| session_length | user  |
+----------------+-------+
| 08:20:37       | user1 |
| 00:01:04       | user2 |
+----------------+-------+

Но опять же мне нужен сброс, чтобы 2 сеанса пользователя user1 не группировались.

Это то, что я пытаюсь сделатьс указанными данными даже возможно, или мне нужен другой столбец "session_id" (или какой-то такой), чтобы помочь с запросом

1 Ответ

0 голосов
/ 04 марта 2019

К сожалению, как вы правильно догадались, вам потребуется поле 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...