【问题标题】:Find overlapping time between two timestamp in postgresql在 postgresql 中查找两个时间戳之间的重叠时间
【发布时间】:2020-07-13 04:31:58
【问题描述】:

我在 postgers 中有一张表,其架构与此类似。

id            start_time            end_time
1    2019-10-21 20:00:00 UTC    2019-10-21 23:00:00 UTC
2    2019-10-21 22:00:00 UTC    2019-10-22 02:00:00 UTC

我想编写一个查询,它会给我在数据库本身中的重叠持续时间。

例如:给定两个输入 t1=2019-10-21 21:00:00 UTC t2=2019-10-22 01:00:00 UTC 查询应该计算输入范围之间的所有重叠时间

输入与第一行的重叠时间为2 hrs 输入和第 2 行之间的重叠时间是 3 hrs 结果将是 2 + 3 = 5

【问题讨论】:

  • 我不明白为什么第二行的重叠应该是 4 小时。对我来说只有三个小时(从 22:00 到次日 01:00)
  • 是的,应该是 3. 编辑问题。谢谢

标签: sql postgresql date datetime group-by


【解决方案1】:

听起来好像您正在寻找两个 tsrange 值的交集:

tsrange(start_time, end_time, '[]') * tsrange('2019-10-21 21:00:00', '2019-10-22 01:00:00', '[]')

'[]' 指定两条边都应包含在范围内。这可能是也可能不是您想要的。您需要根据自己的要求进行调整。

这将返回一个范围类型。要计算范围的长度,请从下限值中减去上限值:

select sum(upper(diff) - lower(diff))
from (
   select tsrange(start_time, end_time, '[]') * tsrange('2019-10-21 21:00:00', '2019-10-22 01:00:00', '[]') as diff
   from the_table
) t

这会返回一个interval,表示所有重叠的总和。

如果您的列是timestamp with time zone,则需要改用tstzrange

Online example

【讨论】:

  • 对于 10k 行,最好(就性能而言)在数据库本身或应用程序中进行此计算?
【解决方案2】:

您可以使用日期算术和聚合:

select 
    sum(
        greatest(
            least(d.end_time, t.end_time) - greatest(d.start_time, t.start_time), 
            '0 hour'::interval
        )
    ) total_overlap
from mytable t
cross join (values 
    ('2019-10-21 21:00:00'::timestamp, '2019-10-22 01:00:00'::timestamp)
) d(start_time, end_time)

对于每一行,较小的结束时间和最大的开始时间之间的差异为您提供重叠的持续时间 - 如果它是正数。

【讨论】:

    猜你喜欢
    • 2017-05-12
    • 1970-01-01
    • 2014-07-12
    • 2020-04-12
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多