如何将所有子组合并为一行并保持相同顺序

时间:2019-03-25 21:37:22

标签: sql oracle gaps-and-islands

这是我的桌子的简化版本

+----+----------+------------+------------+
| ID | Category | Start Date | End Date   |
+----+----------+------------+------------+
|  1 | 'Alpha'  | 2018/04/12 | 2018/04/15 |
|  2 | null     | 2018/04/17 | 2018/04/21 |
|  3 | 'Gamma'  | 2018/05/02 | 2018/05/07 |
|  4 | 'Gamma'  | 2018/05/09 | 2018/05/11 |
|  5 | 'Gamma'  | 2018/05/11 | 2018/05/17 |
|  6 | 'Alpha'  | 2018/05/17 | 2018/05/23 |
|  7 | 'Alpha'  | 2018/05/23 | 2018/05/24 |
|  8 | null     | 2018/05/24 | 2018/06/02 |
|  9 | 'Beta'   | 2018/06/12 | 2018/06/16 |
| 10 | 'Beta'   | 2018/06/16 | 2018/06/20 |
+----+----------+------------+------------+

所有开始日期都是唯一的,不能为空,并且它们与ID的顺序相同(如果a和b是ID,而

我正在寻找可以给我以下结果的查询

+----------+------------+------------+
| Category | Start Date | End Date   |
+----------+------------+------------+
| 'Alpha'  | 2018/04/12 | 2018/04/15 |
| null     | 2018/04/17 | 2018/04/21 |
| 'Gamma'  | 2018/05/02 | 2018/05/17 |
| 'Alpha'  | 2018/05/17 | 2018/05/24 |
| null     | 2018/05/24 | 2018/06/02 |
| 'Beta'   | 2018/06/12 | 2018/06/20 |
+----------+------------+------------+

注意:“结束日期”将等于子组(相同的连续类别)中最后一行的结束日期。

2 个答案:

答案 0 :(得分:1)

这是一个孤岛问题。我认为您可以使用行号的不同之处:

select category, min(startdate), max(enddate)
from (select t.*,
             row_number() over (order by id) as seqnum,
             row_number() over (partition by category order by id) as seqnum_c
      from t
     ) t
group by category, (seqnum - seqnum_c)
order by  min(startdate);

答案 1 :(得分:0)

这是一个gaps and islands问题,您可以在下面使用这样的逻辑

select category, min(start_date) as start_date, max(end_date) as end_date
  from
(
select tt.*, sum(grp) over (order by id, start_date) sm 
  from
(
    with t( ID, Category, Start_Date, End_Date) as
    (
     select  1 , 'Alpha'  , date'2018-04-12',date'2018-04-15' from dual union all
     select  2 , null     , date'2018-04-17',date'2018-04-21' from dual union all
     select  3 , 'Gamma'  , date'2018-05-02',date'2018-05-07' from dual union all
     select  4 , 'Gamma'  , date'2018-05-09',date'2018-05-11' from dual union all
     select  5 , 'Gamma'  , date'2018-05-11',date'2018-05-17' from dual union all
     select  6 , 'Alpha'  , date'2018-05-17',date'2018-05-23' from dual union all
     select  7 , 'Alpha'  , date'2018-05-23',date'2018-05-24' from dual union all
     select  8 , null     , date'2018-05-24',date'2018-06-02' from dual union all
     select  9 , 'Beta'   , date'2018-06-12',date'2018-06-16' from dual union all
     select 10 , 'Beta'   , date'2018-06-16',date'2018-06-20' from dual
    )    
 select id, Category, 
        decode(nvl(lag(end_date) over 
                   (order by end_date),start_date),start_date,0,1) 
                   as grp, --> means prev. value equals or not 
        row_number() over (order by id, end_date) as rn, start_date, end_date
    from t
) tt
order by rn
) 
group by Category, sm 
order by end_date;

CATEGORY  START_DATE    END_DATE    
Alpha     12.04.2018    15.04.2018 
NULL      17.04.2018    21.04.2018 
Gamma     02.05.2018    07.05.2018 
Gamma     09.05.2018    17.05.2018 
Alpha     17.05.2018    24.05.2018 
NULL      24.05.2018    02.06.2018 
Beta      12.06.2018    20.06.2018