我有一个包含事件和Unix时间戳的表:
event_id | start_time | end_time
----------------------------------
1 | 1485388800 | 1485410400
2 | 1485396000 | 1485403200
3 | 1485406800 | 1485414000
我想写一个查询,它需要一个开始时间和一个结束时间,并告诉我每小时发生了多少事件。上表的结果,给定开始时间1485385200和结束时间1485414000将是:
event_count | time
------------------------
0 | 1485385200
1 | 1485388800
1 | 1485392400
2 | 1485396000
2 | 1485399600
1 | 1485403200
2 | 1485406800
1 | 1485410400
0 | 1485414000
编写此查询的最佳方法是什么?我既坚持产生这个范围又坚持检查事件的范围,最好不要多次读表,因为它可能非常大。
答案 0 :(得分:1)
正如评论中所提到的,最好的办法是让某种日历表加入。
然而,这是一个(略微hacky)解决方案,没有使用这样的表。它使用变量生成小时序列。
您唯一需要记住的是,您需要一个足够大的表来表示您尝试创建的间隔数(即一个表的记录数至少与您选择的开始和结束时间之间的小时数)。在我的示例中,我使用了内置的mysql.help_topic
表,但如果您的events
表本身足够大,则可以使用该表(或任何其他表)。
SET @x:=1485385200, @y:=1485414000;
SELECT COUNT(event_id) AS event_count, hours.start AS time
FROM (
SELECT @x AS start, @x := @x + 3600 AS end
FROM mysql.help_topic
WHERE @x <= @y
) AS hours
LEFT JOIN events AS e
ON e.start_time < hours.end AND e.end_time > hours.start
GROUP BY hours.start
这为您提供的测试数据提供了以下输出:
+-------------+------------+
| event_count | time |
+-------------+------------+
| 0 | 1485385200 |
| 1 | 1485388800 |
| 1 | 1485392400 |
| 2 | 1485396000 |
| 2 | 1485399600 |
| 1 | 1485403200 |
| 2 | 1485406800 |
| 1 | 1485410400 |
| 0 | 1485414000 |
+-------------+------------+
答案 1 :(得分:0)
看起来有点乱,但有效。我们的想法是使用联合制作一个日历表并将其与您的表连接。您可以根据您的要求传递开始时间和结束时间,我已经完成了24小时
SELECT count(event_id) as event_count,t
FROM
(
SELECT
DATE_FORMAT(FROM_UNIXTIME(`start_time`), '%Y-%m-%d %H:%i:%s') as start_time,
DATE_FORMAT(FROM_UNIXTIME(`end_time`), '%Y-%m-%d %H:%i:%s') as end_time,
tmp.*,
event_id
from test
right JOIN
(
(select concat(date(now()),' ','00:00') as t)
UNION
(select concat(date(now()),' ','01:00') as t)
UNION
(select concat(date(now()),' ','02:00') as t)
UNION
(select concat(date(now()),' ','03:00') as t)
UNION
(select concat(date(now()),' ','04:00') as t)
UNION
(select concat(date(now()),' ','05:00') as t)
UNION
(select concat(date(now()),' ','06:00') as t)
UNION
(select concat(date(now()),' ','07:00') as t)
UNION
(select concat(date(now()),' ','08:00') as t)
UNION
(select concat(date(now()),' ','09:00') as t)
UNION
(select concat(date(now()),' ','10:00') as t)
UNION
(select concat(date(now()),' ','11:00') as t)
UNION
(select concat(date(now()),' ','12:00') as t)
UNION
(select concat(date(now()),' ','13:00') as t)
UNION
(select concat(date(now()),' ','14:00') as t)
UNION
(select concat(date(now()),' ','15:00') as t)
UNION
(select concat(date(now()),' ','16:00') as t)
UNION
(select concat(date(now()),' ','17:00') as t)
UNION
(select concat(date(now()),' ','18:00') as t)
UNION
(select concat(date(now()),' ','19:00') as t)
UNION
(select concat(date(now()),' ','20:00') as t)
UNION
(select concat(date(now()),' ','21:00') as t)
UNION
(select concat(date(now()),' ','22:00') as t)
UNION
(select concat(date(now()),' ','23:00') as t)
)tmp
on(cast(tmp.t as datetime) between DATE_FORMAT(FROM_UNIXTIME(`start_time`), '%Y-%m-%d %H:%i:%s') and DATE_FORMAT(FROM_UNIXTIME(`end_time`), '%Y-%m-%d %H:%i:%s'))
)xxx
group by t