在PostgreSQL

时间:2016-01-26 20:36:24

标签: sql postgresql

假设我有一张看起来像这样的表:

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 1pmquery_end = Jan 15 at 3pm之间所有时间的总和。这很简单,因为我可以查找start >= query_startend <= query_end的时间,然后总结startend之间的差异。

然而,当查询范围不完全包含行中的范围时,它会变得更复杂。

例如,如果我在Jan 15 2:15 pmJan 15 2:35 pm之间的所有时间进行查询,那么正确的结果将是5分钟,因为在该时间之间有5分钟的行1

另外,例如,如果我的查询范围介于Jan 15 2:40Jan 15 2:41之间,那么我希望总计1分钟。

我真正需要的是总和,而不是单独的行。

PostgreSQL本机支持吗?

如果没有,是否有人对如何编写函数有任何想法?

2 个答案:

答案 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)');

根据您希望的结果,将范围调整为打开或关闭。