如何填补日期范围空白 Oracle SQL

How to fill date range gaps Oracle SQL

对于给定的数据集:

WITH ranges AS (
select to_date('01.01.2021 00:00:00','DD.MM.YYYY hh24:mi:ss') date_from,
    to_date('31.03.2021 00:00:00','DD.MM.YYYY hh24:mi:ss') date_to 
from dual 
union
select to_date('27.03.2021 00:00:00','DD.MM.YYYY hh24:mi:ss') date_from,
    to_date('27.04.2021 00:00:00','DD.MM.YYYY hh24:mi:ss') date_to
from dual 
union
select to_date('01.05.2021 00:00:00','DD.MM.YYYY hh24:mi:ss') date_from,
    to_date('31.12.2021 00:00:00','DD.MM.YYYY hh24:mi:ss') date_to 
from dual 
)
SELECT * FROM ranges;

如何找到 28.04.2021-30.04.2021. 的差距?还要考虑到两者之间可能存在多个间隙并且范围可以重叠。

有什么建议吗?

试试这个查询,根据您的需要调整:

WITH steps AS (
  SELECT date_from as dt, 1 as step FROM ranges
   UNION ALL
  SELECT date_to as dt, -1 as step FROM ranges
)
SELECT dt as dt_from,
       lead(dt) over (order by dt) as dt_to,
       sum(step) over (order by dt) as cnt_ranges
  FROM steps;


dt_from                 | dt_to                   | cnt_ranges
------------------------+-------------------------+-----------
2021-01-01 00:00:00.000 | 2021-03-27 00:00:00.000 | 1
2021-03-27 00:00:00.000 | 2021-03-31 00:00:00.000 | 2
2021-03-31 00:00:00.000 | 2021-04-27 00:00:00.000 | 1
2021-04-27 00:00:00.000 | 2021-05-01 00:00:00.000 | 0
2021-05-01 00:00:00.000 | 2021-12-31 00:00:00.000 | 1
2021-12-31 00:00:00.000 |                         | 0

您对日期范围的建模不正确;例如,在 02-14-2021 午夜结束的时间间隔应该 而不是 包括 02-14-2021。在你的模型中它确实如此。

这会导致您针对模型编写的所有查询出现不必要的复杂情况。在下面的解决方案中,我需要先将结束日期加 1,进行所有处理,然后在最后减去 1。

with
  ranges (date_from, date_to) as (
    select to_date('01.01.2021 00:00:00','DD.MM.YYYY hh24:mi:ss'),
           to_date('31.03.2021 00:00:00','DD.MM.YYYY hh24:mi:ss')
    from   dual
    union  all
    select to_date('27.03.2021 00:00:00','DD.MM.YYYY hh24:mi:ss'),
           to_date('27.04.2021 00:00:00','DD.MM.YYYY hh24:mi:ss')
    from   dual 
    union  all
    select to_date('01.05.2021 00:00:00','DD.MM.YYYY hh24:mi:ss'),
           to_date('31.12.2021 00:00:00','DD.MM.YYYY hh24:mi:ss') 
    from   dual 
)
select first_missing, last_missing - 1 as last_missing
from   (
         select dt                          as first_missing, 
                lead(df) over (order by dt) as last_missing
         from   (select date_from, date_to + 1 as date_to from ranges)
         match_recognize(
           order by date_from
           measures first(date_from) as df, max(date_to) as dt
           pattern  (a* b)
           define   a as max(date_to) >= next (date_from)
         )
       )
where  last_missing is not null
;

FIRST_MISSING       LAST_MISSING       
------------------- -------------------
28.04.2021 00:00:00 30.04.2021 00:00:00