“差距和孤岛”问题通常通过应用一个窗口函数来检查数据的变化并根据这些变化分配一个组号来解决。
首先,需要根据时间戳列定义的排序顺序将当前值与前一个值进行比较:
此声明:
select *,
case
when abc is null or lag(abc) over (order by "date") is not null then null
else 1
end as group_flag
from data
order by "date";
返回这个结果:
date | abc | group_flag
--------------------+-----+-----------
2016-04-18 07:10:00 | 2.3 | 1
2016-04-18 07:20:00 | 2.1 |
2016-04-18 07:30:00 | |
2016-04-18 07:40:00 | |
2016-05-01 10:00:00 | 1.9 | 1
2016-05-01 10:10:00 | 4.5 |
2016-05-01 10:20:00 | 3.9 |
如您所见,每次新“组”开始时,我们都会收到一个标志。
下一步是使用运行总和,将“标志”更改为实际组:
select *,
sum(group_flag) over (order by date) as group_nr
from (
select *,
case
when abc is null lag(abc) over (order by "date") is not null then null
else 1
end as group_flag
from data
) t1
order by "date";
这会返回:
date | abc | group_flag | group_nr
--------------------+-----+------------+---------
2016-04-18 07:10:00 | 2.3 | 1 | 1
2016-04-18 07:20:00 | 2.1 | | 1
2016-04-18 07:30:00 | | | 1
2016-04-18 07:40:00 | | | 1
2016-05-01 10:00:00 | 1.9 | 1 | 2
2016-05-01 10:10:00 | 4.5 | | 2
2016-05-01 10:20:00 | 3.9 | | 2
如您所见,新列 group_nr 现在标识了我们感兴趣的连续期间。对于您的结果,我们只需过滤掉 abc 为空的那些行:
select min(date) as period_start, max(date) as period_end
from (
select *,
sum(group_flag) over (order by date) as group_nr
from (
select *,
case
when abc is null or lag(abc) over (order by date) is not null then null
else 1
end as group_flag
from data
) t1
order by "date"
) t2
where abc is not null
group by group_nr;
这会返回:
period_start | period_end
--------------------+--------------------
2016-04-18 07:10:00 | 2016-04-18 07:20:00
2016-05-01 10:40:00 | 2016-05-01 11:00:00