繁体   English   中英

如何计算 SQL 中的重叠日期范围

[英]How to calculate overlapping date range in SQL

我正在尝试从重叠日期范围列表中识别日期范围。 例如,我的日期范围如下。

START_DATE  END_DATE
01-SEP-19   04-OCT-19
01-OCT-19   30-OCT-19
05-OCT-19   20-OCT-19
31-OCT-19   15-NOV-19

从这里我想计算重叠的日期范围,然后从那里计算日期范围的各个部分。 我想要的 output 在下面

START_DATE  END_DATE
01-SEP-19   30-SEP-19
01-OCT-19   04-OCT-19
05-OCT-19   20-OCT-19
21-OCT-19   30-OCT-19
31-OCT-19   15-NOV-19

任何关于如何进行此操作的建议都会有所帮助。

在 Oracle 13 中进行测试

您可以使用以下查询:

-- Your Test data:
WITH r(START_DATE,  END_DATE)  AS 
  (SELECT date'2019-09-01', date'2019-10-04' from dual union all
   SELECT date'2019-10-01', date'2019-10-30' from dual union all
   SELECT date'2019-10-05', date'2019-10-20' from dual union all
   SELECT date'2019-10-31', date'2019-11-15' from dual)
   , start_dates AS (SELECT start_date FROM r
                      UNION
                     -- Add the end dates that lie within one of the given ranges:
                     SELECT end_date + 1 FROM r e
                      WHERE EXISTS (SELECT 1 FROM r 
                                     WHERE e.end_date + 1  BETWEEN r.start_date AND r.end_date))
SELECT s.start_date
     , LEAST (-- Get the minimal end_date where the start_date is within the range
              (SELECT MIN(end_date) FROM r
                WHERE s.start_date BETWEEN r.start_date AND r.end_date)
              -- If there is start_date -1 prior to this end_date take this instead
              ,NVL((SELECT MIN(start_date) - 1 FROM r
                     WHERE s.start_date < r.start_date)
                  ,DATE'9999-12-31')) AS END_DATE
  FROM start_dates s

结果:

START_DATE  END_DATE
01-SEP-19   30-SEP-19
01-OCT-19   04-OCT-19
05-OCT-19   20-OCT-19
21-OCT-19   30-OCT-19
31-OCT-19   15-NOV-19

您将结束日期包括在日期范围内。 仅当结束日期被认为是一个日期范围(从午夜到午夜)时才有效。 由于 Oracle “日期”包含时间组件,我强烈建议将 Oracle “日期”视为时间点。 在这种情况下,最好说结束日期时间不包括在范围内。 关于时间有效性的 SQL 标准遵循这种方法。

作为奖励,使用“独占”结束日期可以使此类问题变得更容易。

我通过在查询开始时将结束日期加 1 并在结束查询之前减 1 来解决此问题。 请参阅https://stewashton.wordpress.com/2018/11/26/ranges-with-nulls-05-segments/了解说明以及如何处理日期范围内的 NULL。

create table t(START_DATE, END_DATE) as
select to_date('01-SEP-19','dd-mon-yy'), to_date('04-OCT-19','dd-mon-yy') from dual union all
select to_date('01-OCT-19','dd-mon-yy'), to_date('30-OCT-19','dd-mon-yy') from dual union all
select to_date('05-OCT-19','dd-mon-yy'), to_date('20-OCT-19','dd-mon-yy') from dual union all
select to_date('31-OCT-19','dd-mon-yy'), to_date('15-NOV-19','dd-mon-yy') from dual;

with unpivoted as (
  select * from (
    select start_date, end_date + 1 end_date from t
  )
  unpivot(start_date for seg_start in(start_date as 1, end_date as -1))
)
select start_date, end_date - 1 end_date, NUM_SEGS
from (
  select u.*,
  lead(start_date) over(order by start_date) end_date,
  sum(seg_start) over(order by start_date) num_segs
  from unpivoted u
)
where num_segs > 0 and start_date < end_date;

START_DATE END_DATE     NUM_SEGS
---------- ---------- ----------
2019-09-01 2019-09-30          1
2019-10-01 2019-10-04          2
2019-10-05 2019-10-20          2
2019-10-21 2019-10-30          1
2019-10-31 2019-11-15          1

最好的问候,炖阿什顿

您可以尝试以下查询 SQL 中的重叠日期范围:

 select * from t t1
          join t t2 on 
             (t1.START_DATE > t2.START_DATE and t1.START_DATE < t2.END_DATE  )
          or (t1.END_DATE   > t2.START_DATE and t1.END_DATE   < t2.END_DATE  )
          or (t1.END_DATE   > t2.END_DATE   and t1.START_DATE < t2.START_DATE)

这将提供我相信的日期范围。 找到这个日期范围后,我们可以对主表进行另一个左连接,以确定哪个(开始日期或结束日期)属于这些日期范围。

create table date_range
as 
select * 
from  
( 
    select "START_DATE" as dt
    from "CUST_name" 
    union
    select "END_DATE" 
    from "CUST_name" 
    union 
    select "START_DATE"
    from "CUST_PH" 
    union
    select "END_DATE" 
    from "CUST_PH" 
) x 
order by dt

select dt, nvl((LEAD (dt,1) OVER (ORDER BY dt)) -1, date '9999-12-31') AS next_dt
from date_range order by dt

DT  NEXT_DT
01-SEP-19   30-SEP-19
01-OCT-19   03-OCT-19
04-OCT-19   04-OCT-19
05-OCT-19   19-OCT-19
20-OCT-19   29-OCT-19
30-OCT-19   30-OCT-19
31-OCT-19   14-NOV-19
15-NOV-19   31-DEC-99

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM