【问题标题】:Find the date after a gap in date range in sql在sql中查找日期范围间隙后的日期
【发布时间】:2025-12-10 08:20:05
【问题描述】:

我有这些代表订阅开始和结束日期的日期范围。日期范围没有重叠。

Start Date   End Date
1/5/2015 -  1/14/2015
1/15/2015 - 1/20/2015
1/24/2015 - 1/28/2015
1/29/2015 - 2/3/2015

我想确定任何订阅结束与新订阅开始之间超过 1 天的延迟。例如对于上面的数据,我想要输出:1/24/2015 - 1/28/2015.

如何使用 sql 查询来做到这一点?

编辑:订阅日期范围也可能有多个间隔,但我希望日期范围在最新的日期范围之后。

【问题讨论】:

  • 你的逻辑不清楚。请阅读How-to-Ask这里是START的好地方
  • 我认为这很清楚。下一行的end datestart date 之间的“差距”应该超过 1 天。
  • 不,不清楚。可能存在多少差距?
  • 不管有多少空隙,他都想把它们都找出来。因此他需要遍历每条记录并查询start_date > {{row_end_date + 1 day}},然后他才能推断出他的差距。不幸的是,我不知道如何直接在 sql 中执行此操作,我必须使用 ORM 进行迭代。您很可能需要使用这样的存储过程:*.com/questions/5817395/…
  • 但他说他想识别“延迟”,然后输出“开始日期 - 结束日期”。我放弃了,对不起。

标签: sql date


【解决方案1】:

您使用left joinnot exists 执行此操作:

select t.*
from t
where not exists (select 1
                  from t t2
                  where t2.enddate = dateadd(day, -1, t.startdate)
                 );

请注意,这也会为您提供序列中的第一条记录。 . .严格来说,符合条件。这是解决该问题的一种方法:

select t.*
from t cross join
     (select min(startdate) as minsd from t) as x
where not exists (select 1
                  from t t2
                  where t2.enddate = dateadd(day, -1, t.startdate)
                 ) and
      t.startdate <> minsd;

您也可以使用窗口函数来解决这个问题:

select t.*
from (select t.*,
             lag(enddate) over (order by startdate) as prev_enddate,
             min(startdate) over () as min_startdate
      from t
     ) t
where minstartdate <> startdate and
      enddate <> dateadd(day, -1, startdate);

另请注意,此逻辑假定时间段不重叠。如果他们这样做了,则需要更清晰的问题陈述来了解您真正在寻找什么。

【讨论】:

    【解决方案2】:

    您可以使用窗口函数LAG() 来实现此目的,该函数将从有序集中的前一行获取值,以便稍后在WHERE 子句中进行比较。然后,在WHERE 中,您只需应用您的“间隙定义”并丢弃第一行。

    SQL FIDDLE - Test it!

    样本数据:

    create table dates(start_date date, end_date date);
    
    insert into dates values 
      ('2015-01-05','2015-01-14'),
      ('2015-01-15','2015-01-20'),
      ('2015-01-24','2015-01-28'), -- gap
      ('2015-01-29','2015-02-03'),
      ('2015-02-04','2015-02-07'),
      ('2015-02-09','2015-02-11'); -- gap
    

    查询

    SELECT
      start_date,
      end_date
    FROM (
      SELECT
        start_date,
        end_date,
        LAG(end_date, 1) OVER (ORDER BY start_date) AS prev_end_date
      FROM dates
      ) foo
    WHERE
      start_date IS DISTINCT FROM ( prev_end_date + 1 ) -- compare current row start_date with previous row end_date + 1 day
      AND prev_end_date IS NOT NULL -- discard first row, which has null value in LAG() calculation
    

    我假设您的数据中没有重叠,并且每一对都有唯一值。如果不是这种情况,您需要澄清这一点。

    【讨论】: