Oracle-加入2个时间段

时间:2018-12-20 10:47:56

标签: oracle oracle12c

我有2行和2个时间段相交。例如:

---------------------------------------------
|     START_DATE      |      END_DATE       |
---------------------------------------------
| 01/01/2018 08:00:00 | 01/01/2018 09:30:00 |
| 01/01/2018 08:30:00 | 01/01/2018 10:00:00 |
---------------------------------------------

两个时段相隔30分钟。我想避免它。我想将两行合并为一列,以开始日期为旧日期,以结束日期为新日期:

---------------------------------------------
|     START_DATE      |      END_DATE       |
---------------------------------------------
| 01/01/2018 08:00:00 | 01/01/2018 10:00:00 |
---------------------------------------------

您知道如何通过SQL语句获得所需的解决方案吗?

2 个答案:

答案 0 :(得分:1)

对于两行,只需使用greatest()least()。但是问题是当您有许多行可能以不同的方式重叠时。您可以:

  • 在每行中添加行号,
  • 使用递归查询为重叠时段分配组,
  • 使用此值对数据进行分组,并找到每个组中的最大日期和最小日期。

dbfiddle demo

with 
    r(rn, start_date, end_date) as (
        select row_number() over(order by start_date), start_date, end_date from t ),
    c(rn, start_date, end_date, grp) as (
        select rn, start_date, end_date, 1 from r where rn = 1
        union all
        select r.rn, 
               case when r.start_date <= c.end_date and c.start_date <= r.end_date 
                    then least(r.start_date, c.start_date) else r.start_date end,
               case when r.start_date <= c.end_date and c.start_date <= r.end_date 
                    then greatest(r.end_date, c.end_date) else r.end_date end,
               case when r.start_date <= c.end_date and c.start_date <= r.end_date 
                    then grp else grp + 1 end
          from c join r on r.rn = c.rn + 1)
select min(start_date), max(end_date) from c group by grp

答案 1 :(得分:0)

如果您只有一组日期范围,没有其他相关或约束条件,并且希望将其减少为一组不重叠的范围,则可以使用像这样的递归查询来做到这一点:

with recur(start_date, end_date) as (
  select * from yourdata yd 
   where not exists (select 1 from yourdata cyd 
                      where yd.start_Date between cyd.start_date and cyd.end_date
                        and (yd.start_date <> cyd.start_date or yd.end_date <> cyd.end_date))
  union all
  select r.start_date
       , yd.end_date
    from recur r
    join yourdata yd
      on r.start_date < yd.start_date
     and yd.start_date <= r.end_date
     and r.end_date < yd.end_date
)
select start_date, max(end_date) end_Date from recur group by start_Date;

在此查询中,锚点(所有并集之前的部分)选择开始日期未包含在任何其他范围内的所有记录。

然后,递归部分(所有并集之后的部分)选择扩展当前范围的范围。在这两个部分中,将返回原始开始日期,而在递归部分中,将返回新的扩展结束日期。这样会导致一组重叠的范围和起始日期相同。

最后,输出查询返回按开始日期分组的开始日期和最大结束日期。

相关问题