假设我们有看起来像的数据:
drop table if exists views;
create table views(id int primary key,start time,end time);
insert into views values
(1, '15:01', '15:04'),
(2, '15:02', '15:09'),
(3, '15:12', '15:15'),
(4, '16:11', '16:23'),
(5, '16:19', '16:25'),
(6, '17:52', '17:59'),
(7, '18:18', '18:22'),
(8, '16:20', '16:22'),
(9, '18:17', '18:23');
像这样很容易想象
1 |-----|
2 |-----|
3 |--|
4 |-----|
5 |-----|
6 |---|
7 |---|
8 |---|
9 |-----|
现在我想绘制数据图表,看起来像这样
+---------------------------+
| x |
| x x xxx xxx |
| x xx xx x xx x |
+---------------------------+
本质上是将它们分成 X 长度的片段,并计算每个 X 长度片段被触摸的次数。关于如何创建此 View 有任何想法吗?
(如果您必须知道这一点,那么我可以为视频分析创建参与数据)
我不希望输出为 ASCII,我希望它最终作为 SQL 中的查询结果。像这样的东西:
Time Start, Time End, Num_Views
00:00, 00:05, 10
00:06, 00:10, 3
00:11, 00:15, 2
00:16, 00:20, 8
最佳答案
使用辅助数字表,你可以做这样的事情:
select
r.Time_Start,
r.Time_End,
sum(v.id is not null) as Num_Views
from (
select
cast(from_unixtime((m.minstart + n.n + 0) * 300) as time) as Time_Start,
cast(from_unixtime((m.minstart + n.n + 1) * 300) as time) as Time_End
from (
select
unix_timestamp(date_format(minstart, '1970-01-01 %T')) div 300 as minstart,
unix_timestamp(date_format(maxend , '1970-01-01 %T')) div 300 as maxend
from (
select
min(start) as minstart,
max(end ) as maxend
from views
) s
) m
cross join numbers n
where n.n between 0 and m.maxend - minstart
) r
left join views v on v.start < r.Time_End and v.end > r.Time_Start
group by
r.Time_Start,
r.Time_End
;
对于您的特定示例,此脚本产生以下输出:
Time_Start Time_End Num_Views
---------- -------- ---------
15:00:00 15:05:00 2
15:05:00 15:10:00 1
15:10:00 15:15:00 1
15:15:00 15:20:00 0
15:20:00 15:25:00 0
15:25:00 15:30:00 0
15:30:00 15:35:00 0
15:35:00 15:40:00 0
15:40:00 15:45:00 0
15:45:00 15:50:00 0
15:50:00 15:55:00 0
15:55:00 16:00:00 0
16:00:00 16:05:00 0
16:05:00 16:10:00 0
16:10:00 16:15:00 1
16:15:00 16:20:00 2
16:20:00 16:25:00 3
16:25:00 16:30:00 0
16:30:00 16:35:00 0
16:35:00 16:40:00 0
16:40:00 16:45:00 0
16:45:00 16:50:00 0
16:50:00 16:55:00 0
16:55:00 17:00:00 0
17:00:00 17:05:00 0
17:05:00 17:10:00 0
17:10:00 17:15:00 0
17:15:00 17:20:00 0
17:20:00 17:25:00 0
17:25:00 17:30:00 0
17:30:00 17:35:00 0
17:35:00 17:40:00 0
17:40:00 17:45:00 0
17:45:00 17:50:00 0
17:50:00 17:55:00 1
17:55:00 18:00:00 1
18:00:00 18:05:00 0
18:05:00 18:10:00 0
18:10:00 18:15:00 0
18:15:00 18:20:00 2
18:20:00 18:25:00 2
数字表可以是临时表,但我建议您创建并初始化一个永久表,因为它可用于多种用途。这是初始化数字表的一种方法:
create table numbers (n int);
insert into numbers (n) select 0;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
insert into numbers (n) select cnt + n from numbers, (select count(*) as cnt from numbers) s;
/* repeat as necessary; every repeated line doubles the number of rows */
可以找到此脚本的“实时”版本on SQL Fiddle .
UPDATE(尝试描述所使用的方法)
上述解决方案实现了以下步骤:
在
views
表中找到最早的start
时间和最晚的end
时间。将两个值都转换为 unix timestamps .
将两个时间戳除以 300,这实际上为我们提供了相应 5 分钟范围的索引(自大纪元以来)。
在数字表的帮助下,生成一系列 5 分钟的范围,涵盖
start
和end
之间的整个范围。将范围列表与
views
表中的事件时间进行匹配(使用外部联接,因为我们想要(如果我们想要)考虑所有范围)。按范围界限对结果进行分组并计算组中的事件数。 (而且我刚刚注意到上面查询中的
sum(v.id is not null)
可以替换为更简洁,在本例中更自然的count(v .id)
.)
关于mysql - 使用 MySQL 聚合重叠事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10344191/