我有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语句获得所需的解决方案吗?
答案 0 :(得分:1)
对于两行,只需使用greatest()
和least()
。但是问题是当您有许多行可能以不同的方式重叠时。您可以:
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;
在此查询中,锚点(所有并集之前的部分)选择开始日期未包含在任何其他范围内的所有记录。
然后,递归部分(所有并集之后的部分)选择扩展当前范围的范围。在这两个部分中,将返回原始开始日期,而在递归部分中,将返回新的扩展结束日期。这样会导致一组重叠的范围和起始日期相同。
最后,输出查询返回按开始日期分组的开始日期和最大结束日期。