我有一张表,其中有效的开始日期和结束日期是员工的历史数据。该表应包含该员工的所有详细信息。
我需要通过查询找出日期之间有间隔的地方。例如:
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 NO 1和3,存在差距。例如,对于2010年8月29日之后和2010年20月20日之前的第1号,应该有一个记录。 同样在emp no。 3应该在2010年3月21日至2010年3月29日之间有记录。
我可以为此编写什么查询
答案 0 :(得分:2)
这是一个典型的 Gaps and Islands 问题。您需要找出日期序列中的缺失值。
例如,
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语句。实际上,您需要使用自己的 table_name 而不是 sample_data 。
答案 1 :(得分:2)
您还可以通过比较每一行的start_date与同一员工的前一个end_date来找到解决方案:
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
答案 2 :(得分:1)
最简单的方法是将行的结束日期与下一行的开始日期进行比较。您可以使用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
N.B。你没有说出你期望看到的那种输出,所以我已经给你了差距的开始和结束日期。
此外,和Lalit一样,我在WITH子句中使用了子查询来生成示例数据。你不需要那个子查询,因为你已经有了一个&#34; abc&#34;表