此问题已被问及before,但我遇到的问题略有不同。
我有一个记录事件并存储其时间戳的表(作为日期时间)。我需要能够将时间分解成块并获得在该间隔中发生的事件的数量。间隔可以是自定义的(比如5分钟到1小时甚至更长)。
显而易见的解决方案是将datetime转换为unix_timestamp,将其除以间隔中的秒数,取其底层函数并将其乘以秒数。最后将unix_timestamp转换回日期时间格式。
这适用于小间隔。
select
from_unixtime(floor(unix_timestamp(event.timestamp)/300)*300) as start_time,
count(*) as total
from event
where timestamp>='2012-08-03 00:00:00'
group by start_time;
这样可以得到正确的输出
+---------------------+-------+
| start_time | total |
+---------------------+-------+
| 2012-08-03 00:00:00 | 11 |
| 2012-08-03 00:05:00 | 4 |
| 2012-08-03 00:10:00 | 4 |
| 2012-08-03 00:15:00 | 7 |
| 2012-08-03 00:20:00 | 8 |
| 2012-08-03 00:25:00 | 1 |
| 2012-08-03 00:30:00 | 1 |
| 2012-08-03 00:35:00 | 3 |
| 2012-08-03 00:40:00 | 3 |
| 2012-08-03 00:45:00 | 5 |
~~~~~OUTPUT SNIPPED~~~~~~~~~~~~
但如果我将间隔增加到1小时(3600秒)
mysql> select from_unixtime(floor(unix_timestamp(event.timestamp)/3600)*3600) as start_time, count(*) as total from event where timestamp>='2012-08-03 00:00:00' group by start_time;
+---------------------+-------+
| start_time | total |
+---------------------+-------+
| 2012-08-02 23:30:00 | 35 |
| 2012-08-03 00:30:00 | 30 |
| 2012-08-03 01:30:00 | 12 |
| 2012-08-03 02:30:00 | 18 |
| 2012-08-03 03:30:00 | 12 |
| 2012-08-03 04:30:00 | 4 |
| 2012-08-03 05:30:00 | 3 |
| 2012-08-03 06:30:00 | 13 |
| 2012-08-03 07:30:00 | 269 |
| 2012-08-03 08:30:00 | 681 |
| 2012-08-03 09:30:00 | 1523 |
| 2012-08-03 10:30:00 | 911 |
+---------------------+-------+
据我所知,未正确设置边界的原因是unix_timestamp会将时间从我的本地时区(GMT + 0530)转换为UTC,然后输出数值。
所以像2012-08-03 00:00:00这样的值实际上是2012-08-02 18:30:00。划分和使用楼层会将分钟部分设置为00.但是当我使用from_unixtime时,它会将其转换回GMT + 0530,因此我会在30分钟内开始间隔。
无论时区如何,如何确保查询正常工作?我使用MySQL 5.1.52所以to_seconds()不可用
修改 无论间隔(可以是小时,分钟,天),查询也应该正确触发。一般的解决方案将不胜感激
答案 0 :(得分:7)
您可以使用TIMESTAMPDIFF
按时间间隔进行分组:
对于指定的小时间隔,您可以使用:
SELECT '2012-08-03 00:00:00' +
INTERVAL FLOOR(TIMESTAMPDIFF(HOUR, '2012-08-03 00:00:00', timestamp) / <n>) * <n> HOUR AS start_time,
COUNT(*) AS total
FROM event
WHERE timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time
用最小输入日期替换2012-08-03 00:00:00
的出现次数。
<n>
是指定的时间间隔小时(每2
小时,3
小时等),您可以在几分钟内执行相同操作:
SELECT '2012-08-03 00:00:00' +
INTERVAL FLOOR(TIMESTAMPDIFF(MINUTE, '2012-08-03 00:00:00', timestamp) / <n>) * <n> MINUTE AS start_time,
COUNT(*) AS total
FROM event
WHERE timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time
<n>
指定的时间间隔为分钟(每45
分钟,90
分钟等)。
请确保您将最小输入日期(在此示例中为2012-08-03 00:00:00
)作为TIMESTAMPDIFF
的第二个参数传递。
编辑: 如果您不想担心在TIMESTAMPDIFF
功能中选择哪个间隔单位,那么当然只需要按秒(300 = 5分钟,3600 = 1小时,7200 = 2小时等)
SELECT '2012-08-03 00:00:00' +
INTERVAL FLOOR(TIMESTAMPDIFF(SECOND, '2012-08-03 00:00:00', timestamp) / <n>) * <n> SECOND AS start_time,
COUNT(*) AS total
FROM event
WHERE timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time
EDIT2: 要解决与减少必须通过最小参数日期的语句中区域数量相关的注释,您可以使用:
SELECT b.mindate +
INTERVAL FLOOR(TIMESTAMPDIFF(SECOND, b.mindate, timestamp) / <n>) * <n> SECOND AS start_time,
COUNT(*) AS total
FROM event
JOIN (SELECT '2012-08-03 00:00:00' AS mindate) b ON timestamp >= b.mindate
GROUP BY start_time
只需将最小日期时间参数传递到join子选择中。
您甚至可以在连接子选择中为秒间隔(例如3600
)创建第二列,并将列命名为secinterval
...然后更改<n>
到b.secinterval
,所以你只需要传递最小日期参数和间隔一次。
答案 1 :(得分:1)
更简单的方法是:
方法1
select date(timestamp) as date_timestamp, hour(timestamp) as hour_timestamp, count(*) as total
from event
where timestamp>='2012-08-03 00:00:00'
group by date_timestamp, hour_timestamp
如果您想使用原始方法。
方法2
select from_unixtime(floor(unix_timestamp(event.timestamp-1800)/3600)*3600+1800) as start_time,
count(*) as total
from event
where timestamp>='2012-08-03 00:00:00'
group by start_time;
对于第一种方法,它还允许用户设置不同的间隔。 例如,如果用户希望日志分组15分钟,
select date(time) as date_timestamp,
hour(time) as hour_timestamp,
floor(minute(time) as minute_timestamp / 15) * 15 as minute_timestamp
count(*) as total
from event
group by date_timestamp, hour_timestamp, minute_timestamp