如何在Postgres中对时间段进行逻辑运算?

时间:2018-06-13 15:04:04

标签: postgresql period

我有一些时间段:

Mobile Event Time
  A    START 13:00
  B    START 13:05
  A    STOP  14:00
  B    STOP  14:05
  A    START 15:00
  A    STOP  16:00

我如何对这些数据进行逻辑运算,以便我得到:

Mobile Event Time
A | B  START 13:00
A | B  STOP  14:05
A | B  START 15:00
A | B  STOP  16:00

Mobile Event Time
A & B  START 13:05
A & B  STOP  14:00

1 个答案:

答案 0 :(得分:1)

如果我理解你的要求,那么"逻辑运算"可能不是描述这些的最佳方式;他们确实设置了交叉和联合操作(尽管两者密切相关)。

的Postgres' range operators可以计算联合和交叉点,因此可能有助于首先将开始/结束时间戳(如your previous question)配对以构建tsrange values

一旦到位,找到交叉点(A & B)相对简单:

WITH time_pair AS (
  SELECT *, lead("time") OVER (PARTITION BY mobile ORDER BY "time") AS next_time
  FROM events
  WHERE event IN ('START', 'STOP')
),
time_range AS (
  SELECT mobile, tsrange("time", next_time) AS period
  FROM time_pair
  WHERE event = 'START'
)
SELECT 'A & B', a_range.period * b_range.period
FROM time_range a_range
JOIN time_range b_range ON
  a_range.period && b_range.period
WHERE
  a_range.mobile = 'A' AND
  b_range.mobile = 'B';

联盟(A | B)更多参与;如果一个范围在两端都重叠,则每个输出行都有(至少)三个范围,因此单个JOIN就不够了。

另一方面,这个问题有点笼统,因为您可以将任何重叠范围合并在一起,而不考虑它们来自哪个用户,因此查找现有实现会更容易一些。 This answer似乎相当全面。您可以通过搜索"postgres range aggregation"找到更多内容。