我有一组机器。他们偶尔跑步和停止。这些运行时间会自动记录到postgres表中,时间戳为starttime
和endtime
。
我需要在6小时内找到每台机器的运行时间。这就是我到目前为止所做的:
SELECT machine, SUM(EXTRACT(EPOCH FROM (endtime - starttime)))
FROM table
WHERE
starttime >= '2016-01-27 12:00:00'
AND starttime <= '2016-01-27 18:00:00'
GROUP BY machine
ORDER BY machine
这样可行,我可以在一段时间内通过机器获得运行时间。但它有一个缺陷 - 任何在12:00之前开始的运行时间都不会被计算在内。任何在我的时间框架内开始的运行时间,但是在它有时间计数之后才会结束,不应该在那里。
是否有解决方案只能提取时间范围内的时间?我最初的想法是选择所有行:
endtime >= '2016-01-27 12:00:00'
以某种方式,在内存中,将所有开始时间设置为'2016-01-27 12:00:00'
其中开始时间早于和:
starttime <='2016-01-27 18:00:00'
并且,在没有更新数据库的情况下再次在内存中,将所有结束时间设置为'2016-01-27 18:00:00'
,其中结束时间晚于此时间。然后运行提取/求和查询。
但是我在努力实现这样的事情。我有一个使用Java / Python的工作解决方案,这些数据被返回,但它们是迭代的并且花费的时间比我想要的多。如果可能的话,我真的很想找到一个SQL解决方案。
编辑:为了澄清,我需要计算在时间范围内发生的所有运行时间 - 如果运行在时间范围之前开始,那么只有在该时间范围之后发生的那部分运行应该被计算在内。
答案 0 :(得分:1)
您可以使用重叠运算符:
SELECT machine, SUM(EXTRACT(EPOCH FROM (endtime - starttime)))
FROM table
where (starttime, endtime) overlaps (timestamp '2016-01-27 12:00:00', timestamp '2016-01-27 18:00:00')
GROUP BY machine
ORDER BY machine
答案 1 :(得分:1)
编辑:这就是你需要的。
当它在范围之间开始并在之后结束时,它将在18:00:00结束它。
同样适用于在范围和之前开始之间结束时,它将在12:00:00
开始计算SELECT machine, SUM(EXTRACT(EPOCH FROM (endtime - starttime)))
FROM (SELECT machine,
case when starttime <= '2016-01-27 12:00:00' then '2016-01-27 12:00:00' else starttime end as starttime,
case when endtime>= '2016-01-27 18:00:00' then '2016-01-27 18:00:00' else endtime end as endtime, FROM table
WHERE
(endtime>= '2016-01-27 12:00:00'
AND endtime <= '2016-01-27 18:00:00')
OR (starttime>= '2016-01-27 12:00:00'
AND starttime<= '2016-01-27 18:00:00')
GROUP BY machine
ORDER BY machine
答案 2 :(得分:1)
使用类型tsrange及其intersection运算符。
示例数据:
create table machines (machine int, starttime timestamp, endtime timestamp);
insert into machines values
(1, '2016-01-27 10:00:00', '2016-01-27 14:00:00'),
(2, '2016-01-27 15:00:00', '2016-01-27 16:00:00'),
(3, '2016-01-27 17:00:00', '2016-01-27 20:00:00');
此查询将时间范围舍入返回给定时间段:
select
machine,
tsrange(starttime, endtime)*
'[2016-01-27 12:00:00, 2016-01-27 18:00:00)'::tsrange t
from machines;
machine | t
---------+-----------------------------------------------
1 | ["2016-01-27 12:00:00","2016-01-27 14:00:00")
2 | ["2016-01-27 15:00:00","2016-01-27 16:00:00")
3 | ["2016-01-27 17:00:00","2016-01-27 18:00:00")
(3 rows)
从以上数据集中获取聚合:
select
machine,
sum(extract(epoch from (upper(t) - lower(t))))
from (
select
machine,
tsrange(starttime, endtime)*
'[2016-01-27 12:00:00, 2016-01-27 18:00:00)'::tsrange t
from machines
) sub
group by 1
order by 1;
machine | sum
---------+------
1 | 7200
2 | 3600
3 | 3600
(3 rows)