Sql 查询以查找表中日期的间隔

Sql 查询以查找表中日期的间隔,sql,oracle,gaps-and-islands,Sql,Oracle,Gaps And Islands,我有一个带有有效开始日期和结束日期的表,这是员工的历史数据。此表应包含th员工的所有详细信息 我需要通过查询找出日期之间是否有中断。例如: Table ABC : EMP_NO EFF_START_DATE EFF_END_DATE ORG NAME DOB STATUS 1 01-JAN-2010 28-MAR-2010 XYZ SMITH

我有一个带有有效开始日期和结束日期的表,这是员工的历史数据。此表应包含th员工的所有详细信息

我需要通过查询找出日期之间是否有中断。例如:

Table ABC :

EMP_NO  EFF_START_DATE   EFF_END_DATE          ORG             NAME          DOB          STATUS  
1       01-JAN-2010       28-MAR-2010         XYZ             SMITH         10-JAN-1990   SINGLE   
1       29-MAR-2010       29-AUG-2010         XYZ             SMITH         10-JAN-1990   MARRIED
1       20-OCT-2010       31-DEC-4712         XYZ             SMITH         10-JAN-1990   DIVORCEE 

2       04-FEB-2010       28-MAR-2010         XYZ             JOHN        10-JAN-1991   SINGLE   
2       29-MAR-2010       31-DEC-4712         XYZ             JOHN        10-JAN-1991   MARRIED 

3       02-FEB-2010       21-MAR-2010         XYZ             GEETA        10-JAN-1991   SINGLE   
3       29-MAR-2010       31-DEC-4712         XYZ             GEETA        10-JAN-1991   MARRIED 
现在对于EMP 1号和3号有一个差距。例如,对于2010年8月29日之后和2010年10月20日之前的emp 1号,应该有记录。 同样,在第3号环境管理计划中,应在2010年3月21日至2010年3月29日之间有记录

我可以为此写什么查询?这是一个典型的问题。您需要找出日期序列中缺少的值

比如说,

SQL> WITH sample_data(dates) AS(
  2  SELECT  DATE '2015-01-01' FROM dual UNION
  3  SELECT  DATE '2015-01-02' FROM dual UNION
  4  SELECT  DATE '2015-01-03' FROM dual UNION
  5  SELECT  DATE '2015-01-05' FROM dual UNION
  6  SELECT  DATE '2015-01-06' FROM dual UNION
  7  SELECT  DATE '2015-01-07' FROM dual UNION
  8  SELECT  DATE '2015-01-10' FROM dual UNION
  9  SELECT  DATE '2015-01-11' FROM dual UNION
 10  SELECT  DATE '2015-01-12' FROM dual UNION
 11  SELECT  DATE '2015-01-13' FROM dual UNION
 12  SELECT  DATE '2015-01-20' FROM dual
 13  )
 14 -- end of sample_data mimicking real table
 15  SELECT MIN(missing_dates),
 16         MAX(missing_dates)
 17  FROM
 18    (SELECT missing_dates,
 19   missing_dates - row_number() OVER(ORDER BY missing_dates) rn
 20    FROM
 21   (SELECT min_date - 1 + LEVEL missing_dates
 22   FROM
 23  ( SELECT MIN(dates) min_date , MAX(dates) max_date FROM sample_data
 24  )
 25  CONNECT BY level <= max_date - min_date + 1
 26   MINUS
 27   SELECT dates FROM sample_data
 28   ) )
 29  GROUP BY rn ORDER BY rn;

MIN(MISSING_DATES) MAX(MISSING_DATES)
------------------ ------------------
2015-01-04         2015-01-04
2015-01-08         2015-01-09
2015-01-14         2015-01-19


WITH子句仅用于构建示例数据进行演示,因为您没有提供create和insert语句。实际上,您需要使用自己的表名,而不是示例数据。

您还可以通过比较同一员工的每一行的开始日期和上一个结束日期来找到解决方案:

select 
    src.*, 
    src.start_date - src.prev_end_date gap_days 
  from (
    select 
        out_tab.emp_no, 
        (select max(in_tab.end_date) from ABC in_tab where in_tab.emp_no = out_tab.emp_no and in_tab.end_date < out_tab.start_date) prev_end_date, 
        out_tab.start_date 
      from 
        ABC out_tab 
  ) src
  where 
    start_date - prev_end_date > 1;


    EMP_NO PREV_END_DATE START_DATE   GAP_DAYS
---------- ------------- ---------- ----------
         1 29-AUG-10     20-OCT-10          52 
         3 21-MAR-10     29-MAR-10           8 

最简单的方法是比较一行的结束日期和下一行的开始日期。通过使用LEAD分析功能,您可以轻松做到这一点,如下所示:

with abc as (select 1 emp_no, to_date('01/01/2010', 'dd/mm/yyyy') eff_start_date, to_date('28/03/2010', 'dd/mm/yyyy') eff_end_date, 'XYZ' org, 'SMITH' name, to_date('10/01/1990', 'dd/mm/yyyy') dob, 'SINGLE' status from dual union all
             select 1 emp_no, to_date('29/03/2010', 'dd/mm/yyyy') eff_start_date, to_date('29/08/2010', 'dd/mm/yyyy') eff_end_date, 'XYZ' org, 'SMITH' name, to_date('10/01/1990', 'dd/mm/yyyy') dob, 'MARRIED' status from dual union all
             select 1 emp_no, to_date('20/10/2010', 'dd/mm/yyyy') eff_start_date, to_date('31/12/4712', 'dd/mm/yyyy') eff_end_date, 'XYZ' org, 'SMITH' name, to_date('10/01/1990', 'dd/mm/yyyy') dob, 'DIVORCEE' status from dual union all
             select 2 emp_no, to_date('04/02/2010', 'dd/mm/yyyy') eff_start_date, to_date('28/03/2010', 'dd/mm/yyyy') eff_end_date, 'XYZ' org, 'JOHN' name, to_date('10/01/1990', 'dd/mm/yyyy') dob, 'SINGLE' status from dual union all
             select 2 emp_no, to_date('29/03/2010', 'dd/mm/yyyy') eff_start_date, to_date('31/12/4712', 'dd/mm/yyyy') eff_end_date, 'XYZ' org, 'JOHN' name, to_date('10/01/1990', 'dd/mm/yyyy') dob, 'MARRIED' status from dual union all
             select 3 emp_no, to_date('02/02/2010', 'dd/mm/yyyy') eff_start_date, to_date('21/03/2010', 'dd/mm/yyyy') eff_end_date, 'XYZ' org, 'GEETA' name, to_date('10/01/1990', 'dd/mm/yyyy') dob, 'SINGLE' status from dual union all
             select 3 emp_no, to_date('29/03/2010', 'dd/mm/yyyy') eff_start_date, to_date('31/12/4712', 'dd/mm/yyyy') eff_end_date, 'XYZ' org, 'GEETA' name, to_date('10/01/1990', 'dd/mm/yyyy') dob, 'MARRIED' status from dual)
-- end of mimicking your abc table; you won't need the above subquery, as you already have a table called abc.
select emp_no,
       eff_end_date + 1 gap_start_date,
       next_eff_start_date - 1 gap_end_date,
       org,
       name,
       'UKNOWN' status
from   (select emp_no,
               eff_start_date,
               eff_end_date,
               lead(eff_start_date) over (partition by emp_no order by eff_start_date) next_eff_start_date,
               org,
               name,
               dob,
               status
        from   abc)
where  next_eff_start_date - eff_end_date > 1;

    EMP_NO GAP_START_DATE GAP_END_DATE ORG NAME  STATUS
---------- -------------- ------------ --- ----- ------
         1 30-AUG-2010    19-OCT-2010  XYZ SMITH UKNOWN
         3 22-MAR-2010    28-MAR-2010  XYZ GEETA UKNOWN
注意,你没有说你期望看到的结果,所以我给了你差距的开始和结束日期


此外,与Lalit一样,我在WITH子句中使用了子查询来生成示例数据。您不需要该子查询,因为您已经有了一个abc表。

请参阅@LalitKumarB-您给出的示例。我有一张表,上面有13k名员工,有效开始日期和结束日期如上所示。。。u给出的场景我将不得不考虑在语句中的几个日期…我想要更通用的solution@Lyka所以我不是OP,我没有问这个问题。我想你是想提供OP的链接,而不是我。此外,您提供的链接中的解决方案是针对sql server而不是oracle的。我有一个包含13k名员工的表,其有效开始日期和结束日期如上所示。。。上面的场景u已经给出了,我将不得不考虑几个日期与语句…我想要更通用的solution@divya.trehan573我想您不知道WITH子句,它只是为了构建演示的示例数据。实际上,你需要使用自己的桌子。是的。。但是我已经有了一张表,上面有有效的开始日期和结束日期。对于一个员工,我必须比较这两个日期dates@divya.trehan573查询中有什么您不理解的?只需删除WITH子句,直到注释为止,用表名称替换sample_数据。不需要使用子查询来查找上一个结束日期,您可以只使用LAG分析查询。事实上,使用lead/LAG比使用相关子查询具有更好的性能。