查找非连续日期范围中的差距

时间:2014-09-23 08:25:32

标签: sql oracle gaps-and-islands

我正在尝试找到比较一系列数据范围以找到间隙的方法,但是我需要排除完全在另一个范围内的日期范围。一些示例数据:

PERSON_ID  START_DATE  END_DATE 
0001       01/05/2014  30/11/2014 
0001       01/06/2014  01/08/2014 
0001       01/07/2014  01/11/2014 
0001       01/12/2014  31/03/2015 

我知道我可以使用LEAD函数将一行与下一行比较,看看有没有差距的地方,例如:

SELECT END_DATE 
FROM 
   (SELECT t.*, 
      lead(START_DATE,1) OVER (ORDER BY START_DATE) AS next_date 
    FROM table t 
   ) 
WHERE END_DATE+1<>next_date; 

问题在于这会带来误报。第二行和第三行日期范围完全包含在第一行中,因此不应包括在间隙计算中。我知道我需要修改LEAD函数中的偏移量参数,但我不确定为数百个人ID执行此操作的有效方法。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您可以尝试以下方式:

SELECT person_id
     , start_date + 1 start_date
     , end_date - 1 end_date
FROM
  (SELECT person_id
        , end_date start_date
        , lead(start_date) OVER
            (PARTITION BY person_id
             ORDER BY start_date) end_date
   FROM
     (SELECT person_id
           , start_date
           , max(end_date) KEEP
               (DENSE_RANK LAST
                ORDER BY end_date
                       , start_date
                NULLS LAST) end_date
      FROM
        (SELECT person_id
              , CONNECT_BY_ROOT start_date start_date
              , end_date
         FROM
           (SELECT person_id
                 , start_date
                 , end_date
                 , min(start_date) OVER
                     (PARTITION BY person_id) min_start_date
                 , lag(end_date) OVER
                     (PARTITION BY person_id
                      ORDER BY end_date
                             , start_date) lag_end_date
            FROM mytable)
         START WITH
            (  start_date = min_start_date
            OR start_date > lag_end_date + 1)
         CONNECT BY
                person_id = PRIOR person_id
            AND start_date > PRIOR start_date
            AND (  start_date <= PRIOR end_date + 1
                OR PRIOR end_date IS NULL))
      GROUP BY person_id
             , start_date))
WHERE end_date IS NOT NULL

这将合并重叠范围,例如2014年4月1日至2014年5月31日以及2014年5月1日至2014年6月30日将被视为2014年4月1日至2014年6月30日的单一范围。它还将合并邻接范围,例如2014年4月1日至2014年4月30日以及2014年5月1日至2014年5月31日将被视为2014年4月1日至2014年5月31日的单一范围。如果您不希望如何处理这些条件,则需要更改此查询。

答案 1 :(得分:0)

既然你说你得到了假阳性,你可以通过做这样的事情把它变成阳性:

SELECT * FROM table t where END_DATE
NOT IN (SELECT END_DATE 
FROM 
(SELECT t.*, 
  lead(START_DATE,1) OVER (ORDER BY START_DATE) AS next_date 
FROM table t 
) 
WHERE END_DATE+1<>next_date);

我希望它能为您提供一条线索,让您在不更改偏移量参数的情况下获得所需内容。