MySQL查询时间间隔数据直方图

8

我有一个这种类型的事件输入

event user
event start
event end
event type

将每个用户和开始时间作为主键,逐行插入到MySql表中。

我需要按时间间隔(例如一分钟)查询某种类型的直方图,计算每个时间间隔发生的事件数量。类似于:

SELECT count(*) as hits FROM events 
WHERE type="browsing" 
GROUP BY time_diff("2015-1-1" AND "2015-1-2") / 60 * second

除了编写代码之外,我无法找到任何用SQL实现的方法,有什么想法吗?

示例数据

user, start, end, type
1, 2015-1-1 12:00:00, 2015-1-1 12:03:59, browsing
2, 2015-1-1 12:03:00, 2015-1-1 12:06:00, browsing
2, 2015-1-1 12:03:00, 2015-1-1 12:06:00, eating
3, 2015-1-1 12:03:00, 2015-1-1 12:08:00, browsing

结果应该像这样:
         ^
count    |
browsing |
users    |       *
         |       *  *  *  *
         | *  *  *  *  *  *  *  *
         --|--|--|--|--|--|--|--|--|--> minute
         0  1  2  3  4  5  6  7  8  9 

提供示例数据和期望结果。不太清楚您正在寻找什么。 - Gordon Linoff
1
请在问题中添加示例数据和期望结果。 - Gordon Linoff
@moshebeeri... 这有两个具有挑战性的部分。一个是获取直方图所需的所有时间单位(分钟列表),另一个是进行计算。你有第一个吗? - Gordon Linoff
关于 Select count(*) and hits:如果您想列出两个列,我认为您必须在这里使用逗号(',')而不是 'and'。否则,查询可能只返回一个列,该列是应用 AND 布尔运算符的结果(对于其中两列的值评估为 TRUE 的行,其结果为 TRUE,其他行为 FALSE)。 - das-g
是的,代码是说明性的,现在没问题了。 - moshe beeri
显示剩余4条评论
2个回答

11
您可以使用带有所需级别的group by来完成此操作。以下是使用您提供的数据的示例:
首先,使用以下SQL创建和填充表格。这里的ID列并不是“必需的”,但如果表格将很大或其中包含索引,则建议加上它。
CREATE TABLE `test`.`events` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `user` INT NULL,
  `start` DATETIME NULL,
  `end` DATETIME NULL,
  `type` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));

INSERT INTO events (user, start, end, type) VALUES 
(1, '2015-1-1 12:00:00', '2015-1-1 12:03:59', 'browsing'),
(2, '2015-1-1 12:03:00', '2015-1-1 12:06:00', 'browsing'),
(2, '2015-1-1 12:03:00', '2015-1-1 12:06:00', 'eating'),
(3, '2015-1-1 12:03:00', '2015-1-1 12:08:00', 'browsing');

获取按分钟持续时间和活动数量排序的有序对列表:

可以使用timestampdiff函数轻松编写以下查询:

SELECT 
    TIMESTAMPDIFF(MINUTE, start, end) as minutes,
    COUNT(*) AS numEvents
FROM
    test.events
GROUP BY TIMESTAMPDIFF(MINUTE, start, end)

输出:

minutes      numEvents
3            3
5            1

至于绘图部分,我会在这里留下一个附录。有许多好的库可供选择,您可以研究一下(通常情况下,我们在Stack Overflow上尽量将问题限制在一个帖子中,并且不建议教程或服务,因为它们主要是基于个人观点的)。然而,我在这里提出的查询产生的数据应该很容易在任何主要的库中进行绘图。 - techdude
请查看D3 - http://d3js.org/ 或ChartJS - http://www.chartjs.org/ 以获取一些示例。 - techdude
这是个很酷的想法,但它似乎不符合问题中的示例。例如,在第4分钟,有两个用户在浏览网页,而您的查询似乎没有考虑到这一点。您的查询适用于按时间戳排序的事件,而我的问题涉及间隔。 - moshe beeri
啊,我误解了你的问题。我可能会更新我的答案,但是可能需要几天时间才能完成。 - techdude
1
嗨,如果您有更新的话,我会非常高兴如果您能够发布它。我相信这个问题涉及到SQL普遍没有很好涵盖的一个点,因此在这个领域缺乏知识。 - moshe beeri
好的,我更新了答案(我保留了现有的内容,但是在表格创建下方添加了新内容。关键是使用TIMESTAMPDIFF,并将第一个参数设置为所需的间隔。时间戳差异将允许您将差异转换为所需的单位(秒,分钟,小时等)。数字被向下取整,因此40分钟被视为0小时。我添加了一个示例,它增加了1并放置了<符号。 - techdude

0

我假设您拥有一个包含整数的数字表。 您还拥有$starttime$endtime

以下是获取所需值的一种方法:

select ($starttime + interval n.n - 1 minute) as thetime, n.n as minutes,
       count(sd.user)
from numbers n left join
     sampledata sd
     on $starttime + interval n.n - 1 minute between sd.start and sd.end
where $starttime + interval n.n - 1 minute <= $endtime and
      sd.end >= $starttime and
      sd.start <= $endtime
group by n.n
order by n.n;

10x Gordon,看起来这个解决方案会起作用,基本的想法是加入时间间隔表,在事件时间之间应该有一个间隔。 虽然这个想法解决了我的问题,但我感觉它不是最有效的,也不是奥卡姆剃刀解决方案,特别是当需要检查多个时间序列是否在它们之间发生连续事件时(这是我正在处理的主要问题,例如比较或计数同时浏览网页和听音乐的用户)。 我希望在SQL中有更好的方法来做到这一点。 - moshe beeri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接