MySQL计算应用程序的总登录时间

时间:2014-04-28 10:45:09

标签: mysql sql

我正在尝试为我的应用程序计算每个用户的总登录时间。

我正在为必要的测试数据here提供必要的DDL和DML查询。

我尝试使用此查询来解决我的目的。

select userId,
sum(loginTimeInHour) as loginTimeInHour
from(
    select e1.userId, (TIME_TO_SEC(TIMEDIFF(IFNULL(e2.time,NOW()),e1.time)))/(60*60) as loginTimeInHour from 
    EventLog e1
    left join EventLog e2
    on e1.userId = e2.userId
    and e2.eventType = 'LOGOUT'
    and e1.time < e2.time
    where e1.eventType = 'LOGIN'
    group by e1.id having min(IFNULL(e2.time,NOW()) - e1.time)
) temp
group by userId;

这里我在一个场景中得到了错误的结果。假设任何user1 在时间t1登录,然后假设系统无法为user1捕获注销事件。之后,用户1 在系统中的时间t2再次登录 在时间t3 注销。所以我必须忽略在时间t1发生的第一次登录事件。我的查询不能这样做。我的查询返回(t3-t2)+(t3-t1)。我对此方案的预期结果是(t3-t2)。有什么帮助吗?提前致谢。

3 个答案:

答案 0 :(得分:3)

您可以在没有事件的情况下找到所有登录/注销,并总结间隔;

SELECT e1.userid, SUM(UNIX_TIMESTAMP(COALESCE(e2.time, NOW())) - 
                      UNIX_TIMESTAMP(e1.time))/3600 total 
FROM eventlog e1 
LEFT JOIN eventlog e2
  ON e1.userid = e2.userid AND e2.eventType='LOGOUT' AND e1.time < e2.time
LEFT JOIN eventlog e3
  ON e1.userid = e3.userid AND e1.time < e3.time AND e3.time < e2.time
WHERE e1.eventType='LOGIN' AND e3.time IS NULL
GROUP BY e1.userid

An SQLfiddle to test with

请注意,这(因为您的原始查询)不考虑时区。解决该问题的最佳方法可能是以UTC保存所有时间,并使用UTC_TIMESTAMP()而不是NOW()进行查询。

答案 1 :(得分:2)

您需要检查两个条件。您只需要相邻的登录/注销对。一种方法是找到下一个注销记录。然后,计算它们之间的登录记录数。只选择没有其他登录记录的号码。

我更喜欢&#34;接下来&#34;使用相关子查询进行类型计算,而不是使用非等值和聚合。以下是我将如何编写此查询:

select userid, 
       sum(TIME_TO_SEC(TIMEDIFF(coalesce(el.nextLogoutTime, now()), time))/(60*60)) as loginTimeInHour
from (select el.*,
             (select count(*)
              from EventLog el2
              where el2.userId = el.userId and
                    el2.eventType = 'LOGIN' and
                    el2.time < el.nextLogoutTime and
                    el2.time > el.time
             ) as NumLogIns
      from (select el.*,
                   (select max(time)
                    from EventLog el2
                    where el2.userId = el.userId and
                          el2.eventType = 'LOGOUT' and
                          el2.time > el.time
                   ) as nextLogoutTime
            from EventLog el
            where el.eventType = 'LOGIN'
           ) el
     ) el
where NumLogins = 0
group by el.userid;

答案 2 :(得分:0)

每次登录

  1. 找到下一次注销(稍后以最小距离注销)
  2. 找到下一次登录(稍后以最小距离登录)
  3. 如果下一次登录是在下次登出之前,则忽略登录记录
  4. 这是声明。我希望它有效:

    select 
      userId,
      sum(logintimeinhour) as totallogintimeinhour
    from
    (
      select 
        login.userid, 
        min(time_to_sec(timediff(ifnull(later_logout.time,now()), login.time)))/(60*60) as loginTimeInHour
      from EventLog login
      left join EventLog later_login 
        on later_login.eventType = 'LOGIN' 
        and later_login.userId = login.userId
        and later_login.time > later_login.time
      left join EventLog later_logout 
        on later_logout.eventType = 'LOGOUT' 
        and later_logout.userId = login.userId
        and later_logout.time > later_login.time
      where login.eventType = 'LOGIN'
      group by login.id
      having
        min( ifnull(later_logout.time,now()) ) <=
        min( ifnull(later_login.time,now()) )
    )
    group by userid
    order by userid;