我一直在努力解决sql中的一些棘手问题,在这些问题中,我需要从事件间隔推断资产利用率,并且刚刚了解了Allen's Interval Algebra,这似乎是解决这些问题的关键。
代数描述了间隔之间的13种关系,下图显示了前7种,其余的是相反的(即x之前的y,y与x相交,等等)
但我很难找到如何实施相关操作。
给定我的示例数据,如何才能从sql或plsql中的以下三种操作中获得结果?
分离
减少
找出差距
请查看我的SqlFiddle链接:http://sqlfiddle.com/#!4/cf0cc
原始数据

   start end width
[1]     1  12    12
[2]     8  13     6
[3]    14  19     6
[4]    15  29    15
[5]    19  24     6
[6]    34  35     2
[7]    40  46     7

操作1-分离结果
我希望查询从上面的数据返回disjoint set,其中所有重叠的间隔都被分解成行,这样就不存在重叠。
如何处理这个sql?
     start end width
[1]      1   7     7
[2]      8  12     5
[3]     13  13     1
[4]     14  14     1
[5]     15  18     4
[6]     19  19     1
[7]     20  24     5
[8]     25  29     5
[9]     34  35     2
[10]    40  46     7

操作2-减少结果
如何减少/展平间隔,以便:
不为空(即宽度不为空);
不重叠;
从左到右排列;
甚至不相邻(即两个连续范围之间必须存在非空间隙)
以我为例,这看起来像:
    start end width
[1]     1  29    29
[2]    34  35     2
[3]    40  46     7

操作3-间隙结果
另外,我如何找到差距?
   start end width
[1]    30  33     4
[2]    36  39     4

最佳答案

这里有一个SQLFiddle demo
首先,创建临时表以简化查询,但您可以将这些创建查询放入最终查询中,并在不使用临时表的情况下执行此操作:

create table t as select * from
(
select null s ,"start"-1 as e  from data
union all
select "start" s,null e  from data
union all
select "end"+1 s ,null e  from data
union all
select null s ,"end" e  from data
) d where exists (select "start"
                  from data where d.s between data."start" and data."end"
                               or d.e between data."start" and data."end"
                                );
--Operation 1 - Disjoined Result
create table t1 as select s,e,e-s+1 width from
(
select distinct s,(select min(e) from t where t.e>=t1.s) e from t t1
) t2 where t2.s is not null and t2.e is not null;

--Operation 2 - Reduced Result
create table t2 as
select s,e,e-s+1 width from
(
select s,(select min(d2.e) from t1 d2 where d2.s>=d.s and not exists
          (select s from t1 where t1.s=d2.e+1) ) e
from
t1 d where not exists(select s from t1 where t1.e=d.s-1)
) t2;

--Temp table for Operation 3 - Gaps
create table t3 as
select null s, s-1 e from t2
union all
select e+1 s, null e from t2;

下面是问题:
--Operation 1 - Disjoined Result
select * from t1 order by s;

--Operation 2 - Reduced Result


select * from t2 order by s;

--Operation 3 - Gaps

select s,e,e-s+1 width
from
(
select s,(select min(e) from t3 where t3.e>=d.s) e from t3 d
) t4 where s is not null and e is not null
order by s;

10-06 05:25