假设我有一张看起来像这样的表:
id start end
-----+-----------------------+---------------------
1 | Jan 15 2:30 pm | Jan 15 2:45 pm
2 | Jan 15 3:16 pm | Jan 16 5:14 am
: | : | :
我需要做的是获取特定时间范围之间的持续时间总和。
例如,假设我需要query_start = Jan 15 at 1pm
和query_end = Jan 15 at 3pm
之间所有时间的总和。这很简单,因为我可以查找start >= query_start
和end <= query_end
的时间,然后总结start
和end
之间的差异。
然而,当查询范围不完全包含行中的范围时,它会变得更复杂。
例如,如果我在Jan 15 2:15 pm
和Jan 15 2:35 pm
之间的所有时间进行查询,那么正确的结果将是5分钟,因为在该时间之间有5分钟的行1
。
另外,例如,如果我的查询范围介于Jan 15 2:40
和Jan 15 2:41
之间,那么我希望总计1分钟。
我真正需要的是总和,而不是单独的行。
PostgreSQL本机支持吗?
如果没有,是否有人对如何编写函数有任何想法?
答案 0 :(得分:1)
我没有时间对此进行测试,但我认为你可以在哪里查询而不是开始&gt; query_start和end&lt; query_end你可以做到
query_start < end and query_end > start
作为where子句,它将为您提供任何重叠的句点。然后,不是总结每个时期的结束 - 开始,而是可以用
删除重叠sum(min(end, query_end) - max(query_start, start))
我还没有测试过这个。
答案 1 :(得分:0)
您可以使用ranges来解决此问题。
首先使用&amp;&amp ;;找到您感兴趣的范围像
这样的运算符SELECT * FROM foo WHERE tsrange(start, stop) && tsrange('(2016-01-07 10:30', '2016-01-07 16:30)')
然后使用intersect *运算符剪掉您感兴趣的范围/间隔之外的时间。
SELECT tsrange('(2016-01-07 10:30', '2016-01-07 16:30)') * tsrange('(2016-01-07 13:00', '2016-01-07 13:30)')
剩下的就是总结一下。完整的查询类似于
SELECT
SUM(
upper(tsrange(start, stop) * tsrange('(2016-01-07 10:30', '2016-01-07 16:30)'))
-
lower(tsrange(start, stop) * tsrange('(2016-01-07 10:30', '2016-01-07 16:30)')))
FROM foo WHERE tsrange(start, stop) && tsrange('(2016-01-07 10:30', '2016-01-07 16:30)');
根据您希望的结果,将范围调整为打开或关闭。