Sql 查询以查找表中日期的间隔
我有一个带有有效开始日期和结束日期的表,这是员工的历史数据。此表应包含th员工的所有详细信息 我需要通过查询找出日期之间是否有中断。例如: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
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比使用相关子查询具有更好的性能。