【问题标题】:Searching SQL table for two consecutive missing dates在 SQL 表中搜索两个连续缺失的日期
【发布时间】:2016-02-29 16:55:37
【问题描述】:

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

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

我没有发布代码,因为我完全不知道该怎么做。

谢谢!

【问题讨论】:

  • 问题 - 如果他们错过了三天,您想看到两个不同的两天间隔吗?还是三天的差距?

标签: sql oracle search


【解决方案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        

【讨论】:

    【解决方案2】:

    我解决此问题的高级方法是从动态日期表中进行选择,使用整数计数器从当前 DateTime 中添加或减去,以获得未来或过去所需的尽可能多的日期,然后 LEFT 加入您的数据表到此,按日期排序并选择第一行,或 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 个连续的,或者是否有一个 select 语句可以帮助我将 2 个连续的放在一起?
    • 我在查询中添加了一个答案。干杯。
    • ola,将 Michael 的答案标记为有效答案而不是我的答案是值得的,因为他也有支持答案的代码 :)
    【解决方案3】:
    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 2021-08-19
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多