PostgreSQL查询检测重叠时间范围

时间:2014-09-08 21:27:44

标签: sql postgresql

我在PostgreSQL 9.2中有一个表,看起来像这样(简化):

CREATE TABLE my_features
(
  id integer NOT NULL,
  feature_id integer NOT NULL,
  begin_time timestamp NOT NULL,
  end_time timestamp
)

对于每个feature_id,可能有多行,其时间范围由begin_time / end_time指定。它们可能重叠,但这种情况相对较少。我正在寻找一种快速方法来查找所有没有任何重叠的feature_ids。

我尝试使用窗口函数执行此操作,如下所示:

SELECT feature_id, bool_or(end_time > lead(begin_time) OVER ts_win) OVER ts_win AS overlaps_any
FROM my_features
WINDOW ts_win AS (PARTITION BY feature_id ORDER BY begin_time)

......但这不起作用:

ERROR:  window function calls cannot be nested

算法很简单:通过begin_time为给定feature_id排序行,并检查是否有任何end_time>下一个begin_time(如果有的话)。我怀疑必须有一个简单的方法来做到这一点,也许是使用tsrange函数,但现在似乎无法找到它。

2 个答案:

答案 0 :(得分:19)

这确实可以使用范围类型来完成。

以下选择具有重叠范围的所有行:

select f1.*
from my_features f1
where exists (select 1
              from my_features f2
              where tsrange(f2.begin_time, f2.end_time, '[]') && tsrange(f1.begin_time, f1.end_time, '[]')
                and f2.feature_id = f1.feature_id
                and f2.id <> f1.id);

当您将条件更改为NOT EXISTS时,您会找到那些没有任何重叠范围的条件。

SQLFiddle示例:http://sqlfiddle.com/#!15/40b1e/1

tsrange(f2.begin_time, f2.end_time, '[]')创建一个包含上限和下限的范围。您还可以创建排除其中一个或两个的范围。

更多细节可在手册中找到:
http://www.postgresql.org/docs/current/static/rangetypes.html#RANGETYPES-INCLUSIVITY

&&运算符会检查两个范围是否重叠:http://www.postgresql.org/docs/current/static/functions-range.html

(我只是希望甲骨文有这样的东西......)

答案 1 :(得分:2)

这是一个观察。如果某个要素存在重叠的时间段,则至少有一个时间段与begin_time定义的前一个时间段重叠。 (你可以用另一种方式来看待它。如果没有这样的重叠,那么在一个时间框架和下一个框架之间总是存在间隙,并且没有任何重叠。)

这会导致以下查询以确定重叠:

select f.feature_id
from (select f.feature_id,
             (case when lag(end_time) over (partition by feature_id order by begin_time) > begin_time
                   then 1 else 0
              end) as HasOverlap
      from my_features f
     ) f
group by f.feature_id
having max(HaxOverlap) = 1;