如何填补日期范围空白 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
对于给定的数据集:
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