Предположим, у нас есть следующие записи журнала для трех пользователей:
+----+---------+--------+---------------------+
| id | user_id | type | updated_at |
+----+---------+--------+---------------------+
| 1 | 1 | Login | 2019-06-19 15:00:00 |
| 6 | 2 | Login | 2019-06-19 15:02:00 |
| 2 | 1 | Logout | 2019-06-19 15:03:00 |
| 3 | 1 | Login | 2019-06-19 15:04:00 |
| 7 | 2 | Logout | 2019-06-19 15:05:00 |
| 8 | 2 | Login | 2019-06-19 15:07:00 |
| 4 | 1 | Logout | 2019-06-19 15:08:00 |
| 10 | 3 | Login | 2019-06-19 15:09:00 |
| 5 | 1 | Login | 2019-06-19 15:10:00 |
+----+---------+--------+---------------------+
На основе похожих вопросов, таких как Какой самый простой SQL-запрос для поиска второго по величине значения? или Получив второе по величине значение в таблице MySQL , вы можете сначала создать запрос SELECT
, который возвращает последнюю запись login
, которая будет текущим активным сеансом / логином:
SELECT
user_id,
MAX(updated_at) as max_updated
FROM
user_log
WHERE
type = 'Login'
GROUP BY
user_id
Это даст вам следующий результат:
+---------+---------------------+
| user_id | max_updated |
+---------+---------------------+
| 1 | 2019-06-19 15:10:00 |
| 2 | 2019-06-19 15:07:00 |
| 3 | 2019-06-19 15:09:00 |
+---------+---------------------+
Вы снова присоедините этот результат к таблице user_log
с тем же идентификатором пользователя.
SELECT
a.user_id,
a.type,
a.updated_at,
b.max_updated
FROM
user_log a
LEFT JOIN
(
SELECT
user_id,
MAX(updated_at) as max_updated
FROM
user_log
WHERE
type = 'Login'
GROUP BY
user_id
) b ON a.user_id = b.user_id
Это даст вам следующий результат:
+---------+--------+---------------------+---------------------+
| user_id | type | updated_at | max_updated |
+---------+--------+---------------------+---------------------+
| 1 | Login | 2019-06-19 15:00:00 | 2019-06-19 15:10:00 |
| 1 | Logout | 2019-06-19 15:03:00 | 2019-06-19 15:10:00 |
| 1 | Login | 2019-06-19 15:04:00 | 2019-06-19 15:10:00 |
| 1 | Logout | 2019-06-19 15:08:00 | 2019-06-19 15:10:00 |
| 1 | Login | 2019-06-19 15:10:00 | 2019-06-19 15:10:00 |
| 2 | Login | 2019-06-19 15:02:00 | 2019-06-19 15:07:00 |
| 2 | Logout | 2019-06-19 15:05:00 | 2019-06-19 15:07:00 |
| 2 | Login | 2019-06-19 15:07:00 | 2019-06-19 15:07:00 |
| 3 | Login | 2019-06-19 15:09:00 | 2019-06-19 15:09:00 |
+---------+--------+---------------------+---------------------+
Вы можете использовать столбец max_updated
, чтобы удалить любую строку, в которой столбец updated_at
совпадает.Такой строкой будет «последняя» строка, но, поскольку вам не нужны эти строки (а вместо этого все предыдущие строки), вы фильтруете их с помощью предложения WHERE
(и также фильтруете по type
).
SELECT
a.user_id,
a.type,
a.updated_at,
b.max_updated
FROM
user_log a
LEFT JOIN
(
SELECT
user_id,
MAX(updated_at) as max_updated
FROM
user_log
WHERE
type = 'Login'
GROUP BY
user_id
) b ON a.user_id = b.user_id
WHERE
a.updated_at != b.max_updated AND
type = 'Login'
Это даст вам следующее:
+---------+-------+---------------------+---------------------+
| user_id | type | updated_at | max_updated |
+---------+-------+---------------------+---------------------+
| 1 | Login | 2019-06-19 15:00:00 | 2019-06-19 15:10:00 |
| 1 | Login | 2019-06-19 15:04:00 | 2019-06-19 15:10:00 |
| 2 | Login | 2019-06-19 15:02:00 | 2019-06-19 15:07:00 |
+---------+-------+---------------------+---------------------+
Это выглядит многообещающе, поскольку строки для пользователя 3
больше не существует, у нас есть только Login
записейи логин из текущего / активного сеанса не выбран.Отсюда все просто, используя GROUP BY
и затем LEFT JOIN
в таблице пользователей.
SELECT
u.id,
u.username,
l.type,
l.last_login_date
FROM
users u
LEFT JOIN
(
SELECT
a.user_id,
a.type,
MAX(a.updated_at) AS last_login_date
FROM
user_log a
LEFT JOIN
(
SELECT
user_id,
MAX(updated_at) as max_updated
FROM
user_log
WHERE
type = 'Login'
GROUP BY
user_id
) b ON a.user_id = b.user_id
WHERE
a.updated_at != b.max_updated AND
type = 'Login'
GROUP BY
a.user_id) l ON u.id = l.user_id
Это даст вам следующий результат:
+------+----------+-------+---------------------+
| id | username | type | last_login_date |
+------+----------+-------+---------------------+
| 1 | XX | Login | 2019-06-19 15:04:00 |
| 2 | YY | Login | 2019-06-19 15:02:00 |
| 3 | ZZ | NULL | NULL |
+------+----------+-------+---------------------+