2017-11-08 6 views
0

私は、ユーザーconnection/disconnectionログテーブルを持っている:MySQLの - 合計活動時間の選択ログテーブルから

私の質問は、私がuser_idを選択することができますされ
id user_id timestamp   action 
1 8  2017-05-01 10:25 connect 
2 8  2017-05-01 11:00 disconnect 
3 8  2017-05-01 12:10 connect 
3 15  2017-05-01 12:11 connect 
3 8  2017-05-01 12:10 disconnect 

:例えば8活動時間を時間で一日の間に2017-05-01?私は、時間を接続し、

SELECT u.*,u2.* FROM `user_log` as u 
INNER JOIN `user_log` as u2 ON u2.action = 'disconnect' 
AND u.user_id = u2.user_id AND u.`timestamp` < u2.`timestamp` 
WHERE u.action = 'connect' 
GROUP BY u.id 

最初の行を保つユーザーとdisconnect時間が大きいleft joinユーザーからconnectionsを選択しようとしてい

は、それが働いたが、私はそれが最善のアプローチであるのかはわからないようです、また、ユーザーが05-01に接続されているが05-02を切断したときに覆われていない場合があるので、それは私が05-01 12時、私はこのクエリを使用することができると思う

+0

| user_id | timestamp_login | timestamp_logout' - ユーザーがログインしている間、ログアウトは 'null'です。悪い方法ではありません。 – panther

+0

再生のための@pantherありがとう。しかし、問題は、このテーブル構造が必要である理由である接続と切断の期間中に、ユーザーが多くの不注意な操作を行うことができることです。 – Armen

+0

ああ、わかりませんでした...このテーブル構造を使用して、例は同じであるようです。 – panther

答えて

0

と他の人がコメントしたポスター

は、私は最終的に、この質問に対しての答えを見つけました!私たちは、ID `としてテーブル構造を使用

SELECT *, sum(timestampdiff(minute,`connect_timestamp`,`disconnect_timestamp`)) `totalMinutes` 
FROM (

    SELECT user_id, LEAST(start_date, second_date) AS connect_timestamp, GREATEST(start_date, second_date) AS disconnect_timestamp 
    FROM (

      SELECT l.id, l.user_id,`l`.`timestamp` AS start_date, 
      (CASE 
       WHEN l.action = 'connect' THEN (
        coalesce( 

        (select `li`.`timestamp` 
         from `logs` as `li` 
         where `l`.`user_id`= `li`.`user_id`  
         and `l`.`timestamp` < `li`.`timestamp` 
         and DATE(`l`.`timestamp`) = DATE(`li`.`timestamp`) 
         and `li`.`action` = 'disconnect' 
         order by `l`.`timestamp` 
         limit 1), 
         date_add(date_add(date(`l`.`timestamp`), interval 1 day), interval -1 minute) 
       ) 
      ) 
       WHEN l.action = 'disconnect' THEN (
        coalesce( 

        (select `li`.`timestamp` 
         from `logs` as `li` 
         where `l`.`user_id`= `li`.`user_id`  
         and `l`.`timestamp` > `li`.`timestamp` 
         and DATE(`l`.`timestamp`) = DATE(`li`.`timestamp`) 
         and `li`.`action` = 'connect' 
         order by `l`.`timestamp` 
         limit 1), 
         date_add(date(`l`.`timestamp`), interval 0 minute) 
       ) 
      ) 
      END) as second_date 
      FROM `logs` as `l` 

    ) as t GROUP BY connect_timestamp 

) as t2 GROUP BY user_id, DATE(connect_timestamp) 

MySQL Fiddle Demo

1

までカウントする必要があり意味:

select `user_id`, `date` 
    , sum(timestampdiff(minute,`connectTime`,`disconnectTime`)) `totalMinutes` 
from (
    select `l`.`id`, `l`.`user_id`, date(`l`.`timestamp`) as `date` , `l`.`timestamp` as `connectTime`, `l`.`action` 
     , coalesce( 
      /* finding first row of disconnect logs after this connect log */ 
      (select `li`.`timestamp` 
      from `logs` as `li` 
      where `l`.`user_id`= `li`.`user_id`  /* user_id should be same */ 
       and `l`.`timestamp` < `li`.`timestamp` /* disconnect time should be bigger than connect time */ 
       and `li`.`action` = 'disconnect' 
      order by `l`.`timestamp` 
      limit 1), 
      date_add(date_add(date(`l`.`timestamp`), interval 1 day), interval -1 minute) /* calculate last minute of current date */ 
     ) as `disconnectTime` 
    from `logs` as `l` 
    /* filter connect logs only */ 
    where `l`.`action` = 'connect') `t` 
group by `user_id`, `date`; 

MySQL Fiddle Demo

@ shA.tの助けを借りて
+0

ありがとうございます、これは私が探しているものですが、シナリオウィンチはカバーされていません**ユーザが今日接続している場合:15 disconnected :16日目に見て私たちが見ていたのは、彼がオンラインだったというレポートでした。半分の日に** – Armen

+0

このシナリオのコストが大幅に増えてしまった場合、追加したスケジューラーのような余分な方法を使うことをお勧めします。しかし、別のシナリオを追加して、15から18の3つの追加の行などが必要です。 –

+0

@Armenまた、「カレンダー」を格納する余分なテーブルを追加して、それをより良く管理することをお勧めします。 –

0
select con.user_id,SEC_TO_TIME(sum(TIME_TO_SEC(timediff(dis.timestamp,con.timestamp))))timeinuse 
from(SELECT @a :[email protected]+1 as line,w.user_id,w.id,w.timestamp ,w.action 
from user_log w ,(select @a:= 0)l 
    where w.action = 'connect' order by w.user_id,w.timestamp)con inner join 
    (SELECT @b:[email protected]+1 as line ,w.timestamp,w.user_id 
from user_log w ,(select @b:= 0)l where w.action = 'disconnect' group by w.id,w.user_id 
order by w.user_id,w.timestamp)dis on con.line = dis.line and con.user_id =dis.user_id group by con.user_id;