Как узнать, сколько времени каждый пользователь вошел в систему? - PullRequest
0 голосов
/ 04 января 2019

Как узнать, сколько раз каждый пользователь входил в систему? У меня есть такая таблица:

+----------+--------+---------------------+
| username | action |      timestamp      |
+----------+--------+---------------------+
|      111 | login  | 2019-01-01 16:00:00 |
|      222 | login  | 2019-01-01 16:01:00 |
|      111 | logout | 2019-01-01 16:01:00 |
|      222 | logout | 2019-01-01 16:02:00 |
|      111 | login  | 2019-01-01 16:10:00 |
|      222 | login  | 2019-01-01 16:11:00 |
|      111 | logout | 2019-01-01 16:11:00 |
|      222 | logout | 2019-01-01 16:12:00 |
|      222 | login  | 2019-01-01 16:21:00 |
|      222 | logout | 2019-01-01 16:22:00 |
+----------+--------+---------------------+

На выходе должно быть что-то вроде:

+----------+----------+
| username | log_time |
+----------+----------+
|      111 | 00:02:00 |
|      222 | 00:03:00 |
+----------+----------+

Если возможно, я бы хотел знать, как это сделать без использования временных таблиц.

Ответы [ 3 ]

0 голосов
/ 04 января 2019

Вы можете использовать LEAD для этого во внутреннем запросе, а затем вычислить разность и сумму во внешнем запросе

SELECT username, SUM(TIMESTAMPDIFF(MINUTE, timestamp, next_action)) Minutes
FROM (SELECT username, action, timestamp, 
              LEAD(timestamp) OVER (PARTITION BY username ORDER BY timestamp) next_action
       FROM table) lead
WHERE next_action IS NOT NULL 
  AND action = 'login'
GROUP BY username

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

0 голосов
/ 04 января 2019

Это будет работать для MySql 8.0 ,
при условии, что если для входа в систему пользователя нет строки выхода,
тогда текущая дата и время будут использоваться как время выхода из системы для расчета.
Это также отформатирует результат как hh:mm:ss

with 
t as (
  select t1.username, t1.timestamp login, t2.timestamp logout
  from logs t1 inner join (select * from logs where action = 'logout') t2
  where 
    t1.action = 'login' 
    and 
    t2.timestamp = (
      select min(timestamp) from logs where action = 'logout' and timestamp > t1.timestamp
    )
  union
  select t1.username, t1.timestamp login, now() logout
  from logs t1
  where action = 'login' and not exists (select 1 from logs where username = t1.username and action = 'logout' and timestamp > t1.timestamp)
),

r as (
select 
  username,
  sum(timestampdiff(SECOND, login, logout)) dur
from t
group by username 
),

d as (      
select 
  r.username,  
  r.dur div 3600 hours,
  (r.dur - ((r.dur div 3600) * 3600)) div 60 mins,
  mod(r.dur,60) secs        
from r 
)                     

select 
  username,
  concat(if(hours < 10, concat('0', hours), hours), ':', lpad(mins, 2, '0'), ':', lpad(secs, 2, '0')) log_time                 
from d

См. Демоверсию

0 голосов
/ 04 января 2019

Это первое решение, которое пришло мне в голову, я не знаю, хорошо ли оно работает.

SELECT 
    username
    ,sum(logout - login) AS log_time
FROM (
    SELECT 
        username
        , action_
        , ts AS login
        , lead(ts) over (PARTITION BY username ORDER BY ts asc) AS logout 
    FROM 
        'your_table_name'
ORDER BY username, ts ASC
)a 
WHERE logout IS NOT NULL AND action_ = 'login'
GROUP BY 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...