MYSQL按小时和总和差异分组,但按小时分开结果

时间:2017-09-13 04:46:25

标签: mysql

我有以下数据集

start_time              end_time
2017-09-12 12:08:55     2017-09-12 12:10:57
2017-09-12 12:15:10     2017-09-12 12:19:27
2017-09-12 12:24:54     2017-09-12 12:25:35
2017-09-12 12:27:32     2017-09-12 13:20:25
2017-09-12 13:20:25     2017-09-12 13:22:23
2017-09-12 13:32:01     2017-09-12 13:33:57
2017-09-12 13:45:15     2017-09-12 13:46:38
2017-09-12 13:52:52     2017-09-12 13:54:20
2017-09-12 13:59:28     2017-09-12 14:02:32
2017-09-12 14:04:37     2017-09-12 14:07:34
2017-09-12 14:12:49     2017-09-12 14:13:03
2017-09-12 14:34:09     2017-09-12 14:35:47
2017-09-12 14:40:52     2017-09-12 14:46:46
2017-09-12 14:51:57     2017-09-12 14:54:28

我想找到按小时分组的时差之和。由于一些块在一小时内开始但在下一个块中结束,因此计算的总和不是我想要的。举个例子,如果我们采取2017-09-12 12:27:32 - 2017-09-12 13:20:25这个的差异被加到第12个小时并且从第13个小时被忽略。

我正在使用以下查询进行分组和汇总

SELECT 
DATE_FORMAT(start_time, "%H") as h, 
SEC_TO_TIME(SUM(TIME_TO_SEC(end_time) - TIME_TO_SEC(start_time))) AS timediff 
FROM history 
WHERE start_time BETWEEN '2017-09-12 12:00:00' and '2017-09-12 15:00:00'
GROUP BY hour(start_time)

获得结果

h   timediff
12  00:59:53
13  00:09:49
14  00:13:14

有没有办法打破像2017-09-12 12:27:32 - 2017-09-12 13:20:25这样的区块并将差异分别添加到mysql中的相应小时块?

首选输出

h   timediff
12  00:39:28
13  00:27:42
14  00:15:46

(从2017-09-12 12:27:32 - 2017-09-12 13:20:25,32m 28s应该到12小时区块,20m 25s应该到13h区块)

2 个答案:

答案 0 :(得分:1)

使用mysql子查询。首先将数据划分为每小时,然后尝试添加时间段。

SELECT SEC_TO_TIME(SUM(t.h)) timediff, t.hc FROM 
(
SELECT start_time, end_time,
(  UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP( start_time )  ) h, HOUR( start_time ) hc from history 
WHERE HOUR(end_time) = HOUR(start_time) AND start_time BETWEEN '2017-09-12 12:00:00' and '2017-09-12 15:00:00'
UNION
SELECT start_time, end_time,
(  UNIX_TIMESTAMP( end_time ) - UNIX_TIMESTAMP(DATE_FORMAT(end_time, '%Y-%m-%d %H:00:00'))) call_time, HOUR( end_time ) hc from history 
WHERE HOUR(end_time) > HOUR(start_time) AND start_time BETWEEN '2017-09-12 12:00:00' and '2017-09-12 15:00:00'
UNION
SELECT start_time, end_time,
(  UNIX_TIMESTAMP(DATE_FORMAT(end_time, '%Y-%m-%d %H:00:00')) - UNIX_TIMESTAMP( start_time )  ) call_time, HOUR( start_time ) hc from history 
WHERE HOUR(end_time) > HOUR(start_time) AND start_time BETWEEN '2017-09-12 12:00:00' and '2017-09-12 15:00:00'
) t GROUP BY t.hc

答案 1 :(得分:1)

要将时间范围划分为要分组的不同小时数,您可以将其加入到您感兴趣的小时数的临时表中(未经测试):

set @max_duration_mins:=30;
select
    start_range,
    # overlap between two time ranges is the difference between the greater beginning time and the least ending time (or 0 if that's less than 0)
    sum(greatest(
        0,
        least(
            unix_timestamp(date_add(start_range, interval 1 hour)),
            unix_timestamp(end_time)
        ) -
        greatest(
            unix_timestamp(start_range),
            unix_timestamp(start_time)
        )
    )) total_seconds
from (
    select '2017-09-12 12:00:00' start_range
    union all select '2017-09-12 13:00:00'
    union all select '2017-09-12 14:00:00'
) start_range
cross join history
where start_time between date_sub('2017-09-12 12:00:00', interval @max_duration_mins minute) and '2017-09-12 15:00:00'
group by start_range;

在有无限数量的不同分区的情况下,需要稍微复杂一些的方法,就是将历史记录加入到一个特殊表中,该表可以选择在历史范围内选择多少小时(在您的情况下,这只是0或1)。但除非你感兴趣,否则我不会表明这一点。