Sql-запрос для сопоставления таблицы журнала пользователя с первым, последним и предыдущим действием пользователя - PullRequest
1 голос
/ 29 мая 2019

У меня есть таблица журнала пользователя, разделенная на action_date (имя таблицы - user_action_log), состоящее из миллиардов строк, со столбцами

user_id, action_name, action_date

Примерdata -

+---------+-------------+-------------+
| user_id | action_name | action_date |
+---------+-------------+-------------+
| 123     | login       | 2018-01-30  |
| 123     | logout      | 2018-01-31  |
| 123     | click       | 2018-02-28  |
| 123     | comment     | 2018-02-15  |
| 123     | post        | 2018-03-15  |
+---------+-------------+-------------+

Я хочу написать ETL / sql для преобразования этих данных в нечто подобное (имя таблицы - user_action_record).

user_id (первичный ключ), first_action_date, last_action_date, previous_action_date

Пример выходных данных -

+---------+-------------------+------------------+---------------------------+
| user_id | first_action_date | last_action_date | previous_last_action_date |
+---------+-------------------+------------------+---------------------------+
| 123     | 2018-01-30        | 2018-03-15       | 2018-02-28                |
+---------+-------------------+------------------+---------------------------+

Я попытался разделить проблему на 2 шага -

  1. Вставка новых пользователей, которых нет в user_action_record.
  2. Обновите существующего пользователя, обновив «previous_last_action_date» со значения в «last_action_date» и обновив last_action_date на основе таблицы user_action_log.

Проблема в том, что, поскольку user_action_log разделен на action_date, я могу запрашивать эту таблицу ежедневно (action_date = CURRENT_DATE)

Может ли кто-нибудь помочь мне с sqls заполнить мойтаблица целей в этом случае?

- отредактировано с дополнительной информацией ниже

  1. Исходная и ожидаемая таблица целей в день '2018-01-30'
+---------+-------------+-------------+
| user_id | action_name | action_date |
+---------+-------------+-------------+
| 123     | login       | 2018-01-30  |
| 123     | logout      | 2018-01-30  |
| 123     | click       | 2018-01-30  |
+---------+-------------+-------------+

+---------+-------------------+------------------+---------------------------+
| user_id | first_action_date | last_action_date | previous_last_action_date |
+---------+-------------------+------------------+---------------------------+
| 123     | 2018-01-30        | 2018-01-30       | 2018-01-30                |
+---------+-------------------+------------------+---------------------------+
Исходная и ожидаемая целевая таблица на день '2018-01-31'
+---------+-------------+-------------+
| user_id | action_name | action_date |
+---------+-------------+-------------+
| 123     | login       | 2018-01-30  |
| 123     | logout      | 2018-01-30  |
| 123     | click       | 2018-01-30  |
| 123     | login       | 2018-01-31  |
| 123     | logout      | 2018-01-31  |
+---------+-------------+-------------+

+---------+-------------------+------------------+---------------------------+
| user_id | first_action_date | last_action_date | previous_last_action_date |
+---------+-------------------+------------------+---------------------------+
| 123     | 2018-01-30        | 2018-01-31       | 2018-01-30                |
+---------+-------------------+------------------+---------------------------+
Исходная и ожидаемая целевая таблица на день '2018-02-15'
+---------+-------------+-------------+
| user_id | action_name | action_date |
+---------+-------------+-------------+
| 123     | login       | 2018-01-30  |
| 123     | logout      | 2018-01-30  |
| 123     | click       | 2018-01-30  |
| 123     | login       | 2018-01-31  |
| 123     | logout      | 2018-01-31  |
| 123     | logout      | 2018-02-15  |
| 123     | logout      | 2018-02-15  |
+---------+-------------+-------------+

+---------+-------------------+------------------+---------------------------+
| user_id | first_action_date | last_action_date | previous_last_action_date |
+---------+-------------------+------------------+---------------------------+
| 123     | 2018-01-30        | 2018-02-15       | 2018-01-31                |
+---------+-------------------+------------------+---------------------------+

Ответы [ 2 ]

1 голос
/ 29 мая 2019

Вы можете смоделировать функцию ранжирования в MySQL <8 с помощью самостоятельного объединения на <code>user_id, где строка во второй таблице имеет более поздний action_date:

SELECT u1.*, COUNT(u2.user_id) AS rn
FROM user_action_log u1
LEFT JOIN user_action_log u2 ON u2.user_id = u1.user_id AND u2.action_date > u1.action_date
GROUP BY u1.user_id, u1.action_name, u1.action_date
ORDER BY rn;

Вывод:

user_id action_name action_date rn
123     post        2018-03-15  0
123     click       2018-02-28  1
123     comment     2018-02-15  2
123     logout      2018-01-31  3
123     login       2018-01-30  4

Эту таблицу затем можно использовать как производную таблицу, и мы можем найти previous_last_action_date из строки с rn = 1:

SELECT user_id,
       MIN(action_date) AS first_action_date,
       MAX(action_date) AS last_action_date,
       MAX(CASE WHEN rn = 1 THEN action_date END) AS previous_last_action_date
FROM (SELECT u1.*, COUNT(u2.user_id) AS rn
      FROM user_action_log u1
      LEFT JOIN user_action_log u2 ON u2.user_id = u1.user_id AND u2.action_date > u1.action_date
      GROUP BY u1.user_id, u1.action_name, u1.action_date) ual
GROUP BY user_id

Вывод:

user_id first_action_date   last_action_date    previous_last_action_date
123     2018-01-30          2018-03-15          2018-02-28

Демонстрация по dbfiddle

0 голосов
/ 29 мая 2019

В более ранних версиях MySQL вы можете использовать трюк group_concat() / substring_index():

select user_id,
       min(action_date) as first_action_date,
       max(action_date) as last_action_date,
       substring_index(substring_index(group_concat(action_date order by action_date desc), ',', 2), ',', -1) as second_to_last_date
from user_action_log ual
group by user_id;

Другой альтернативой являются коррелированные подзапросы:

select user_id,
       min(action_date) as first_action_date,
       max(action_date) as last_action_date,
       (select max(ual2.action_date)
        from user_action_log ual2
        where ual2.user_id = ual.user_id and
              ual2.action_date < max(ual.action_date)
      ) as second_to_last_date
from user_action_log ual
group by user_id;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...