Oracle - 基于重叠范围拆分记录

时间:2017-02-18 11:54:22

标签: sql oracle

数据样本:

   id   lowerlimt   upperlimit
    1   5           10  ---Master Record
    2   8           12
    3   3           8
    4   8           9
    5   11          15

在上表中,让我们假设以id=1为主记录的记录。我希望将其他记录与同一表中的第一条记录进行比较,如果它与范围重叠并分配标记,则拆分每条记录。如果重叠分配'Y',则为'N'。 如果它重叠,则将记录部分拆分为两个,一个用于重叠范围,另一个用于非重叠范围。

id  lowerlimt   upperlimit  flag
2   8           10          y
2   10          12          n
3   3           5           n
3   5           8           y
4   8           9           y
5   11          15          n

2 个答案:

答案 0 :(得分:1)

我添加了更多"测试数据"用于测试和插图。主要的计算是将输入范围分解为最多三个(其中一些没有意义并且在最后阶段被消除 - 当输入范围严格地与主记录重叠时,达到最多三个在两个方向)。

为了提高效率,最好只访问每个输入行一次。因此,我不是同时使用union all(最简单的路由),而是同时创建所有三个子范围和相应的标志,结果有九列而不是三列用于子范围和标志。然后我使用unpivot将它们分成不同的行。

with
      test_data ( id, lowerlimit, upperlimit ) as (
        select 1,  5, 10 from dual union all ---Master Record
        select 2,  8, 12 from dual union all
        select 3,  3,  8 from dual union all
        select 4,  8,  9 from dual union all
        select 5, 11, 15 from dual union all
        select 6,  2,  5 from dual union all
        select 7,  1, 14 from dual
      )
-- end of test data (not part of the solution)
-- SQL query begins BELOW THIS LINE (use your actual table name)
select id, lowerlimit, upperlimit, flag
from (
   select id,
                   t.lowerlimit        as x1, least(t.upperlimit, m.ll) as y1, 'n' as f1,
          greatest(t.lowerlimit, m.ll) as x2, least(t.upperlimit, m.ul) as y2, 'y' as f2,
          greatest(t.lowerlimit, m.ul) as x3,       t.upperlimit        as y3, 'n' as f3
   from   test_data t cross join
          ( select lowerlimit ll, upperlimit ul 
            from   test_data
            where  id = 1
          ) m
   where  t.id != 1
     )
unpivot ( ( lowerlimit, upperlimit, flag )
                        for ( x, y, f ) in ( ( x1, y1, f1), (x2, y2, f2), (x3, y3, f3) ) )
where lowerlimit < upperlimit
order by id, lowerlimit   --  if needed
;

<强>输出

ID LOWERLIMIT UPPERLIMIT FLAG
-- ---------- ---------- ----
 2          8         10 y
 2         10         12 n
 3          3          5 n
 3          5          8 y
 4          8          9 y
 5         11         15 n
 6          2          5 n
 7          1          5 n
 7          5         10 y
 7         10         14 n

10 rows selected.

答案 1 :(得分:0)

一种方法是将其分为三个重叠条件,主要是“之前”,“期间”和“之后”。因为您希望每个现有行有多个不同的,所以可以使用union all执行此操作:

select t.id, t.lowerlimit,
       least(tm.lowerlimit, t.upperlimit) as upperlimit,
       'n' as overlaps
from t join
     t tm
     on t.id <> 1 and tm.id = 1 and
        t.lowerlimit < tm.lowerlimit
union all
select t.id,
       greatest(t.lowerlimit, tm.lowerlimit),
       least(t.upperlimit, tm.upperlimit), 'y' as overlaps
from t join
     t tm
     on t.id <> 1 and tm.id = 1 and
        t.lowerlimit <= tm.lowerlimit and
        t.upperlimit >= tm.upperlimit
union all
select t.id, greatest(tm.upperlimit, t.upperlimit),
       t.upperlimit, 'n'
from t join
     t tm
     on t.id <> 1 and tm.id = 1 and
        t.upperlimit > tm.upperlimit;