在SQL表中搜索两个连续的缺失日期

时间:2016-02-29 16:55:37

标签: sql oracle search

我想搜索SQL表并找到两个连续的缺失日期。

例如,第1个人在第1天和第2天插入“日记”条目,错过第3天和第4天,并在第5天输入条目。

我不会发布代码,因为我根本不确定如何执行此操作。

谢谢!

3 个答案:

答案 0 :(得分:1)

这使用LEVEL聚合来构建从第一个条目到最后一个条目的日历日期列表,然后使用LAG()检查上一个日期的给定日期,然后检查这些日期都没有关联的条目找到这两天的差距:

With diary as (
    select to_date('01/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('02/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('04/01/2016','dd/mm/yyyy') entry_dt from dual union all
    --leave two day gap of 5th and 6th
    select to_date('07/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('08/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('10/01/2016','dd/mm/yyyy') entry_dt from dual )
select calendar_dt -1, calendar_dt 
FROM (
        select calendar_dt, entry_dt, lag(entry_dt) over (order by calendar_dt) prev_entry_dt
        from diary 
        RIGHT OUTER JOIN (select min(entry_dt) + lvl as calendar_dt
                         FROM diary
                             ,(select level lvl
                               from dual connect by level < (select max(entry_dt) - min(entry_dt)+1 from diary))
                         group by lvl) ON calendar_dt = entry_dt          
        order by calendar_dt 
        )
where entry_dt is null and prev_entry_dt is null        

返回:

CALENDAR_DT-1,  CALENDAR_DT
05/01/2016,     06/01/2016

我只是在做日历建筑,以简化所有2天的间隙,就好像一个人休息三天,这将是两个重叠的两天间隙(第1-2天和第2-3天)。如果您想要一个更简单的查询来输出两天或更多天的任何间隙的起点和终点,那么以下工作:

With diary as (
    select to_date('01/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('02/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('04/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('07/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('08/01/2016','dd/mm/yyyy') entry_dt from dual union all
    select to_date('10/01/2016','dd/mm/yyyy') entry_dt from dual )
select prev_entry_dt +1 gap_start, entry_dt -1 gap_end 
FROM (
        select entry_dt, lag(entry_dt) over (order by entry_dt) prev_entry_dt
        from diary
        order by entry_dt 
) where entry_dt - prev_entry_dt > 2        

答案 1 :(得分:0)

我对此问题的高级解决方法是从动态日期表中进行选择,使用整数计数器在当前DateTime中添加或减去,以获得未来或过去所需的日期,然后使用LEFT join您的数据表,按日期排序并选择第一行,或N多行具有NULL连接。

所以你的数据最终是

DATE           ENTRY_ID
----           -----
2016-01-01     1
2016-01-02     2
2016-01-03     NULL
2016-01-04     3
2016-01-05     4
2016-01-06     NULL
2016-01-07     NULL
2016-01-08     NULL

您可以从此数据集中选择所需的所有值

答案 2 :(得分:0)

Try this your problem looks like similar to this :-

    Declare @temp Table(id int identity(1,1) not null,CDate smalldatetime ,val int)
    insert into @temp select '10/2/2012',1
    insert into @temp select '10/3/2012',1
    insert into @temp select '10/5/2012',1
    insert into @temp select '10/7/2012',2
    insert into @temp select '10/9/2012',2
    insert into @temp select '10/10/2012',2
    insert into @temp select '10/13/2012',2
    insert into @temp select '10/15/2012',2

    DECLARE @startDate DATE= '10/01/2012'
    DECLARE @endDate DATE= '10/15/2012'

    SELECT t.Id, X.[Date],Val = COALESCE(t.val,0)
    FROM 
        (SELECT [Date] = DATEADD(Day,Number,@startDate)  
        FROM  master..spt_values  
        WHERE Type='P' 
        AND DATEADD(day,Number,@startDate) <= @endDate)X
    LEFT JOIN  @temp t 
    ON X.[Date] = t.CDate


Alternative you can try this :-

WITH dates AS (
     SELECT CAST('2009-01-01' AS DATETIME) 'date'
     UNION ALL
     SELECT DATEADD(dd, 1, t.date) 
       FROM dates t
      WHERE DATEADD(dd, 1, t.date) <= '2009-02-01')
SELECT t.eventid, d.date
  FROM dates d 
  JOIN TABLE t ON d.date BETWEEN t.startdate AND t.enddate