[英]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.