[英]MySQL select time groupings where timestamps overlap from different rows with timezone difference
这个问题似乎与其他人提出的问题不同,因此我将在这里提出。
我有一个MySQL表,该表存储时间戳和往返时间戳,我想从该表中选择分组,以计算出人们何时同时“在线”的分组。 这种疯狂背后的想法是在交叉的时间段内将人们自动分组在一起。 理想的情况是,为这个小组争取最好的时间是很棒的(但这可能是不可能的)。
我有两个表,一个名为“ times”的表用于存储时间,一个名为“ users”的表用于存储用户详细信息,users表还包括一个时差字段(以小时为单位),该字段应应用于时间(所有时间均为以UTC存储)。
这是我的桌子:
Users
userid | timediff
------------------
1 | 0
2 | 0
3 | 1
4 | 4
5 | -8
6 | 2
7 | 2
Times
userid | from | to
1 | 2015-01-13 16:00:00 | 2015-01-13 23:00:00
2 | 2015-01-13 13:00:00 | 2015-01-13 21:00:00
3 | 2015-01-13 14:00:00 | 2015-01-13 22:00:00
4 | 2015-01-13 11:00:00 | 2015-01-13 12:00:00
5 | 2015-01-13 10:00:00 | 2015-01-13 12:00:00
6 | 2015-01-13 11:00:00 | 2015-01-13 12:00:00
7 | 2015-01-13 09:00:00 | 2015-01-13 10:00:00
在理想的世界中,这将使人们像这样分组:
1 | 2015-01-13 16:00:00 | 2015-01-13 23:00:00
2 | 2015-01-13 13:00:00 | 2015-01-13 21:00:00
3 | 2015-01-13 14:00:00 | 2015-01-13 22:00:00
这些人在16:00-21:00之间在一起在线
4 | 2015-01-13 11:00:00 | 2015-01-13 12:00:00
5 | 2015-01-13 10:00:00 | 2015-01-13 12:00:00
6 | 2015-01-13 11:00:00 | 2015-01-13 12:00:00
这些人在11:00-12:00之间在一起在线
(也请注意,为了便于理解,这里没有考虑时差,但如果需要,我很乐意指出这一点)。
仅使用sql可能无法实现,我可能需要使用PHP,由于不确定不确定的最佳方向,因此我没有发布任何示例代码,因为任何指针都很好!
这不是一个超级简单的项目。 它有很多内容,特别是时区偏移量,时间范围比较和重合搜索。
但是,让我们尝试一下。 首先,让我们创建一个视图来处理时区偏移。 我们真的不想一遍又一遍地搞砸那个计算。 这种观点将做到这一点。
CREATE VIEW `utctimes`
AS select `t`.`userid` AS `userid`,
`t`.`from` AS `from`,
`t`.`to` AS `to`,
`t`.`from` + interval `u`.`timediff` hour AS `utcfrom`,
`t`.`to` + interval `u`.`timediff` hour AS `utcto`
from `times` `t`
join `users` `u` on `u`.`userid` = `t`.`userid`;
接下来,让我们自我加入该视图并进行一些时间范围的比较,以找出何时有多个人在线。 要查看一对从/到范围是否重叠,此逻辑会执行此操作。
a.from <= b.to
and b.from <= a.to
如果这两个条件都成立,则可以说服自己这两个范围重叠。
即使其中一个正好在中午开通,而另一个正好在中午关断,我们都假设两者都在线,即使这可能是一个糟糕的假设。
该查询将为我们提供时间范围列表以及每个时间范围内某个时间的在线用户数。 它通过混杂的(因此有些昂贵的)自连接来做到这一点。
select count(*) as users_on,
greatest(a.utcfrom, b.utcfrom) utcfrom,
least(a.utcto, b.utcto) utcto
from utctimes a
join utctimes b on a.userid <> b.userid
where a.utcfrom <= b.utcto
and b.utcfrom <= a.utcto
group by greatest(a.utcfrom, b.utcfrom), least(a.utcto, b.utcto)
order by count(*) desc,
greatest(a.utcfrom, b.utcfrom),
timestampdiff(minute, greatest(a.utcfrom, b.utcfrom),
least(a.utcto, b.utcto)) desc
这将首先给出最受欢迎的范围,然后按受欢迎程度给出其他范围。 确实会产生一些重叠范围。
一旦有了最流行的时间范围,您就可以找出在这些时间范围内哪些用户在线。 例如,此JOIN将做到这一点。
select r.users_on, r.utcfrom online_session_start,
timediff(r.utcto, r.utcfrom) online_session_duration,
q.userid, q.`from`, q.`to`
from utctimes q
join (
select count(*) as users_on,
greatest(a.utcfrom, b.utcfrom) utcfrom,
least(a.utcto, b.utcto) utcto
from utctimes a
join utctimes b on a.userid <> b.userid
where a.utcfrom <= b.utcto
and b.utcfrom <= a.utcto
group by greatest(a.utcfrom, b.utcfrom), least(a.utcto, b.utcto)
) r on q.utcfrom <= r.utcto
and r.utcfrom <= q.utcto
order by 2,3,4
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.