我正在尝试为我的应用程序计算每个用户的总登录时间。
我正在为必要的测试数据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)。有什么帮助吗?提前致谢。
答案 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
请注意,这(因为您的原始查询)不考虑时区。解决该问题的最佳方法可能是以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)
每次登录
这是声明。我希望它有效:
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;