在列表中查找重叠数据

时间:2014-01-22 20:32:41

标签: sql oracle

我试图在此列表中找到一些重叠数据。

我无法将此归为一类。

如何获得如下所示的结果?

表格中的数据:

PLAN_MIN    PLAN_MAX
220554          229079
220554          229079 
2210A5          2210A5 
2210A8          2210A8 
2220A5          2220A5 
2220A8          2220A8 
2230A5          2230A5 
2230A8          2230A8 
260554          267566 
2610A5          2610A5 
2610A8          2610A8 
2620A5          2620A5 
2620A8          2620A8

结果:

PLAN_MIN    PLAN_MAX    PLAN_MIN_1  PLAN_MAX_1
2210A5          2210A5          220554          229079
2210A8          2210A8          220554          229079
2220A5          2220A5          220554          229079
2220A8          2220A8          220554          229079
2230A5          2230A5          220554          229079
2230A8          2230A8          220554          229079      
2610A5          2610A5          260554          267566
2610A8          2610A8          260554          267566
2620A5          2620A5          260554          267566
2620A8          2620A8          260554          267566


create table plan_details
(PLAN_MIN   varchar2(20)
,PLAN_MAX   varchar2(20)
);
insert into plan_details values ('220554','229079' );
insert into plan_details values ('2210A5','2210A5' );
insert into plan_details values ('2210A8','2210A8' );
insert into plan_details values ('2220A5','2220A5' );
insert into plan_details values ('2220A8','2220A8' );
insert into plan_details values ('2230A5','2230A5' );
insert into plan_details values ('2230A8','2230A8' );
insert into plan_details values ('260554','267566' );           
insert into plan_details values ('2610A5','2610A5' );
insert into plan_details values ('2610A8','2610A8' );
insert into plan_details values ('2620A5','2620A5' );
insert into plan_details values ('2620A8','2620A8' );
commit;

2 个答案:

答案 0 :(得分:2)

这是我的方法。每条记录将分配给一个组,指定它所属的“组”。在您的示例中,有两个组。这些组不会重叠,但它们中的行会重叠。

如何找到群组?好吧,一个小组从plan_min值与其他任何内容不重叠的地方开始。然后它继续 - 但不包括 - 计划最小值不重叠的下一行。

因此,以下查询将查找组的起始位置。然后它会计算累积总和来计算组。最后的查询执行join和簿记以获取您请求的格式的数据:

with groups as (
      select pd.*, sum(isbegin) over (order by plan_min) as grp
      from (select pd.*,
                   (select (case when count(*) = 0 then 1 else 0 end)
                    from plan_details pd2
                    where pd2.plan_min < pd.plan_min and
                          pd2.plan_max > pd.plan_min
                   ) as IsBegin
            from plan_details pd
           ) pd
     )
select g.plan_min, g.plan_max, gg.min_plan_min, gg.max_plan_max
from groups g join
     (select grp, min(plan_min) as min_plan_min,
             max(plan_max) as max_plan_max
      from groups
      group by grp
     ) gg
     on g.grp = gg.grp;

这已经在你的SQL小提琴上测试过,所以你可以在那里试试。

编辑:

这是OP的最终答案:

SELECT a.plan_min as plan_min, a.plan_max as plan_max , b.plan_min as range_min,
       b.plan_max as range_max
FROM (SELECT p.*, row_number() OVER (ORDER BY plan_min, plan_max) rnum
      FROM plan_details p
     ) a,
     (SELECT p.*, row_number() OVER (ORDER BY plan_min, plan_max) rnum
      FROM plan_details p
     ) b
WHERE a.rnum <> b.rnum AND
      (a.plan_min between b.plan_min and b.plan_max OR
       a.plan_max between b.plan_min and b.plan_max
      )
ORDER BY 1,2,3,4;

答案 1 :(得分:1)

我把它当作一个谜语。您可以使用此查询获得问题中显示的结果:

select x.PLAN_MIN, x.PLAN_MAX
, (select max(PLAN_MIN) from PLAN_DETAILS
   where PLAN_MIN <= substr(x.PLAN_MIN,1,4)
   and PLAN_MIN not like '%A%'
  ) as PLAN_MIN_1
, (select max(PLAN_MAX) from PLAN_DETAILS 
   where PLAN_MIN <= substr(x.PLAN_MIN,1,4)
   and PLAN_MIN not like '%A%'
  ) as PLAN_MAX_1
from PLAN_DETAILS x
where x.PLAN_MIN like '%A%'
order by 1, 2;