我希望计算表格中显示的时间间隔联合的总时间长度。
例如,给出以下内容:
mysql> SELECT * FROM Temp;
+------+---------------------+---------------------+
| id | start | end |
+------+---------------------+---------------------+
| 1 | 2010-01-01 10:00:00 | 2010-01-01 11:00:00 |
| 2 | 2010-01-01 12:00:00 | 2010-01-01 14:00:00 |
| 3 | 2010-01-01 13:00:00 | 2010-01-01 15:00:00 |
+------+---------------------+---------------------+
我想以某种方式选择总时间长度,在这种情况下是4小时(间隔(10:00,11:00)和(12:00,15:00)联合的总时间长度)。
我不在乎输出是以秒为单位(INT
还是FLOAT
),还是其他任何合理的格式。
值得一提的是,我不确定表中日期的顺序。无法保证以任何方式对开始日期时间或结束日期时间进行排序。我也不能说一个“典型的”日期时间间隔 - 例如,它可能超过一天。
我可以说,任何单个时间间隔都是非负长度。也就是说,对于任何记录,结束日期至少与开始日期一样晚。
我知道如何用简单的编程语言(如Python)完成这项任务;我只是想知道在纯MySQL中是否有一种明智的方法可以做到这一点。如果没有,我会选择所有内容并用其他编程语言处理它。因此,“如果没有一些非常认真的努力,在MySQL中完成这一点是不可能的”也可以作为这个问题的合法答案......
我见过this question这是类似的,但约为tsql
。在那里提出的解决方案是使用MySQL不知道的语法,例如cross apply
,我翻译的尝试失败了。
根据要求,以下是创建示例数据的查询:
CREATE TABLE Temp (id INT, start DATETIME, end DATETIME);
INSERT INTO Temp (id, start, end) VALUES (1, '2010-01-01 10:00', '2010-01-01 11:00');
INSERT INTO Temp (id, start, end) VALUES (2, '2010-01-01 13:00', '2010-01-01 14:00');
INSERT INTO Temp (id, start, end) VALUES (3, '2010-01-01 11:00', '2010-01-01 16:00');
所以数据如下:
+------+---------------------+---------------------+
| id | start | end |
+------+---------------------+---------------------+
| 1 | 2010-01-01 10:00:00 | 2010-01-01 11:00:00 |
| 2 | 2010-01-01 13:00:00 | 2010-01-01 14:00:00 |
| 3 | 2010-01-01 11:00:00 | 2010-01-01 16:00:00 |
+------+---------------------+---------------------+
此示例数据的结果应为6小时。
答案 0 :(得分:1)
<强>声明强>
这可能最好在SQL之外完成
对于那些喜欢痛苦查询的人
您可以创建一个查询,尝试确定表中其他位置是否与end
列重叠的行。如果没有,请尝试找出end
列与最近的start
列gap
之间的时间。
然后从整个表格中取出最大end
,从整个表格中减去最小start
,最后减去gap
列的总数:
select
unix_timestamp(maxEnd)-unix_timestamp(minSt)-sum(case when hasEndOverlap=0 then gap else 0 end) as unionSecs,
(unix_timestamp(maxEnd)-unix_timestamp(minSt)-sum(case when hasEndOverlap=0 then gap else 0 end))/(60*60) as unionHrs
from
(
select c.id,c.`start`,c.`end`,
c.minSt,c.maxEnd,
c.hasEndOverlap,
@prevSt,
unix_timestamp(@prevSt)-unix_timestamp(c.`end`) as gap,
@prevSt := c.`start`
from
(
select t.id,t.`start`,t.`end`,
a.minSt,a.maxEnd,
case when min(te.id) is null and t.`end` != a.maxEnd then 0 else 1 end as hasEndOverlap
from Temp t
left outer join Temp te on t.`end` >= te.`start` and t.`end` <= te.`end` and t.id != te.id
join (select min(`start`) as minSt,max(`end`) as maxEnd from test.`Temp`) a
group by t.id,t.`start`,t.`end`
) c
join (select @prevSt := '1970-01-01') r
order by c.`end` desc
) d
group by minSt,maxEnd
;