PostgreSQL unnest,带有 where 子句的 int4range

PostgreSQL unnest, int4range with where clause

我有一个名为 mytable:

的数据table
╔════╤══════════════════════════════╤══════════╗
║ id │ segments                     │ duration ║
╠════╪══════════════════════════════╪══════════╣
║ 1  │ {"[1,4)","[6,13)","[15,19)"} │ 14       ║
╟────┼──────────────────────────────┼──────────╢
║ 2  │ {"[3,16)","[19,22)"}         │ 16       ║
╚════╧══════════════════════════════╧══════════╝

segments 是以秒为单位的时间间隔数组。
durationsegments 中时间间隔的总和,以秒为单位。

例如id=1,segments中的三个间隔分别为3、7、4秒。他们在 duration.

中总共用了 14 秒

我想从此 table 中仅提取满足两个条件的行:

查询应该只 return id=1 因为它的每个 segments 都不到 10 秒并且它的 duration 至少是 10 秒。

查询不应 return id=2 因为其中一个 segments 的长度为 13 秒。它的 duration 至少是 10 秒,但它不符合第一个条件 segments.

取消横向连接中的数组嵌套,并按 id 计算分组总和。使用布尔聚合 bool_and() 消除小于 10 秒的片段。

select id, segments, sum(elem.upper- elem.lower) as duration
from my_table
cross join unnest(segments) elem
group by id
having bool_and(elem.upper- elem.lower < 10)
and sum(elem.upper- elem.lower) >= 10

Db<>Fiddle.

您可以进行横向连接:

select t.*
from mytable t
inner join lateral (
    select bool_and(seg.upper - seg.lower < 10) to_keep
    from unnest(t.segments) seg 
) x on x.to_keep
where t.duration >+ 10

子查询拆嵌数组,使用bool_or()保证所有间隔小于10秒;连接条件消除了不需要的行。

Demo on DB Fiddle:

id | segments                     | duration
-: | :--------------------------- | -------:
 1 | {"[1,4)","[6,13)","[15,19)"} |       14