Какой тип объединения может объединять записи в одну таблицу SQL? - PullRequest
0 голосов
/ 06 июня 2019

Мне нужно найти и объединить записи в таблице, связанные по времени. В таблице записывается активность пользователя на веб-сайте (время начала и окончания действия).

Я пытаюсь объединить в одну запись любую активность в течение часа после другой активности того же пользователя. Поэтому, если начало одной записи составляет 55 минут после окончания предыдущей активности того же пользователя, я объединяю ее, чтобы создать одну запись.

Я пробовал разные способы самостоятельного соединения, чтобы достичь этого, но результаты никогда не бывают идеальными.

В двух шагах я попробовал это:

  1. Сначала ОБНОВИТЕ updated_at (конец действия), чтобы все записи в течение часа друг от друга имели общую метку updated_at, которая является самой последней в группе.

  2. Удалите все более поздние записи в группе, чтобы остались только самые ранние записи, теперь с самыми ранними созданными_т_ и последними обновленными_т

- Сначала установите общее время окончания (updated_at) для всех действий одного пользователя с менее чем часом между

UPDATE users_activity
SET updated_at = (SELECT a.LatestEnd  FROM (SELECT
    UA1.id,
    MAX(UA2.updated_at) AS LatestEnd
FROM users_activity UA1, users_activity UA2
    WHERE
    UA1.id <> UA2.id
        AND UA1.user_id = UA2.user_id
        AND UA1.created_at > DATE_SUB(UA2.updated_at,INTERVAL 1 HOUR)
        AND UA1.created_at < UA2.updated_at
        ) a)
WHERE
    users_activity.id IN (SELECT b.id  FROM (SELECT
    UA1.id
    FROM users_activity UA1, users_activity UA2
    WHERE
    UA1.id <> UA2.id
        AND UA1.user_id = UA2.user_id
        AND UA1.created_at > DATE_SUB(UA2.updated_at,INTERVAL 1 HOUR)
        AND UA1.created_at < UA2.updated_at
        ) b);
-- next delete all the later records in the group, leaving only the earliest
DELETE FROM users_activity 
WHERE
    users_activity.id IN (SELECT * FROM (SELECT d.id FROM users_activity d 
INNER JOIN
(SELECT
    COUNT(CONCAT(user_id,'_',updated_at)) AS Duplicates,
    CONCAT(user_id,'_',updated_at) AS UserVisitEnd,
    id,
    user_id,
    MAX(created_at) AS LatestStart
FROM users_activity
    GROUP BY UserVisitEnd
    HAVING Duplicates > 1) a on a.LatestStart = d.created_at AND a.user_id = d.user_id) as AllDupes);

Если данные такие:

|id  |user_id|created_at         |updated_at
|5788|1222   |2019-06-06 08:55:28|2019-06-06 09:30:41
|5787|3555   |2019-06-06 08:40:04|2019-06-06 11:07:21
|5786|1222   |2019-06-06 07:11:03|2019-06-06 08:01:29
|5785|7999   |2019-06-05 18:11:03|2019-05-01 18:17:44
|5784|3555   |2019-06-04 16:53:32|2019-06-04 16:58:19
|5783|9222   |2019-04-01 15:21:32|2019-04-01 16:53:32
|5782|1222   |2019-03-29 14:02:09|2019-03-29 15:51:07
|5774|1222   |2019-03-29 13:38:43|2019-03-29 13:50:43
|5773|7999   |2018-09-23 17:38:35|2018-09-23 17:40:35

Я должен получить такой результат:

|id  |user_id|created_at         |updated_at
|5787|3555   |2019-06-06 08:40:04|2019-06-06 11:07:21
|5786|1222   |2019-06-06 07:11:03|2019-06-06 09:30:41
|5785|7999   |2019-06-05 18:11:03|2019-05-01 18:17:44
|5784|3555   |2019-06-04 16:53:32|2019-06-04 16:58:19
|5783|9222   |2019-04-01 15:21:32|2019-04-01 16:53:32
|5774|1222   |2019-03-29 13:38:43|2019-03-29 15:51:07
|5773|7999   |2018-09-23 17:38:35|2018-09-23 17:40:35

Example of data for merging

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

SELECT b.id, b.user_id, b.created_at, b.updated_at, b.UpdatedAtOfSessionToMerge, b.IDofSessionToMerge FROM (SELECT
UA1.id,
UA1.user_id,
UA1.created_at,
UA1.updated_at,
UA2.updated_at AS UpdatedAtOfSessionToMerge,
UA2.id AS IDofSessionToMerge
FROM users_activity UA1, users_activity UA2
WHERE
UA1.id <> UA2.id
    AND UA1.user_id = UA2.user_id
    AND UA1.created_at > DATE_SUB(UA2.updated_at,INTERVAL 1 HOUR)
    AND UA1.updated_at < UA2.updated_at
    AND UA1.created_at < UA2.updated_at
    ) b order by b.user_id;

Ответы [ 3 ]

0 голосов
/ 06 июня 2019

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

SELECT min(ID) as ID, User_ID, Min(Created_At) Created_At, Max(Updated_At) as Updated_At

ИЗ таблицы GROUP BY User_ID, ORDER BY User_ID;

Проверьте следующую ссылку для форматирования дат в MySQL

0 голосов
/ 07 июня 2019

Это ручное решение, достаточное для одноразовой очистки старых данных сеанса. Он использует два соединения SELF, так что может быть более эффективный способ сделать это.

Шаг 1 , Найти пакеты записей сеанса и объединить их, задав им одинаковое значение конца сеанса (updated_at)

UPDATE users_activity as u1 JOIN (SELECT b.id, b.user_id, b.created_at, b.updated_at, b.UpdatedAtOfSessionToMerge, b.IDofSessionToMerge FROM (SELECT
UA1.id,
UA1.user_id,
UA1.created_at,
UA1.updated_at,
UA2.updated_at AS UpdatedAtOfSessionToMerge,
UA2.id AS IDofSessionToMerge
FROM users_activity UA1, users_activity UA2
WHERE
UA1.id <> UA2.id
    AND UA1.user_id = UA2.user_id
    AND UA1.created_at > DATE_SUB(UA2.updated_at,INTERVAL 1 HOUR)
    AND UA1.updated_at < UA2.updated_at
    AND UA1.created_at < UA2.updated_at
    ) b order by b.user_id) as u2
    on u1.id = u2.id
    SET u1.updated_at = u2.UpdatedAtOfSessionToMerge;

Повторяйте этот запрос, пока строки не будут затронуты

Шаг 2 , удаление ненужных записей сеанса в каждом объединенном пакете;

DELETE FROM users_activity 
WHERE
    users_activity.id IN (SELECT * FROM (SELECT d.id FROM users_activity d 
INNER JOIN
(SELECT
    COUNT(CONCAT(user_id,'_',updated_at)) AS Duplicates,
    CONCAT(user_id,'_',updated_at) AS UserVisitEnd,
    id,
    user_id,
    MAX(created_at) AS LatestStart
FROM users_activity
    GROUP BY UserVisitEnd
    HAVING Duplicates > 1) a on a.LatestStart = d.created_at AND a.user_id = d.user_id) as AllDupes);

Повторять этот запрос, пока строки не будут затронуты

0 голосов
/ 06 июня 2019
SELECT min(ID) as ID, User_ID, Min(Created_At) Created_At, Max(Updated_At) as Updated_At
FROM Table
GROUP BY User_ID, DATE_FORMAT(Created_At, "%Y%m%d%H");

Было бы близко, но я не уверен, что справляюсь с "Часовым" накоплением так, как вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...