2016-02-04 2 views
2

У меня есть таблица с эффективной датой начала и датой окончания, которая является историческими данными для сотрудников. В этой таблице должны быть указаны все данные сотрудника.QUERY, чтобы найти пробел в датах в таблице

Мне нужно узнать по запросу, где бывают перерывы между датами. Например:

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 

Теперь для ПУЭ № 1 и 3 есть пробел. Например, для emp no 1 после 29 августа 2010 года и до 20 октября 2010 года должна была быть запись. аналогично в emp no. 3 должны были быть записи между 21 марта 2010 года по 29 марта 2010 года.

, что запрос я могу написать для этого

+0

См. [** Пробелы и острова **] (https://lalitkumarb.com/category/gaps-and-islands/) –

+0

@ LalitKumarB- Пример, который вы указали. \t У меня есть таблица с пояснениями работника 13k с эффективной датой начала и датой окончания, как указано выше ... Сценарий, который вы дали, должен будет рассмотреть только несколько дат с заявлением ..... Я хочу больше общее решение –

+0

@Lyka Итак? Я не ОП, я не задавал вопрос. Я думаю, вы хотели предоставить эту ссылку на OP, а не мне. Кроме того, решение в предоставленной вами ссылке относится к 'sql-server', а не' oracle'. –

ответ

2

Вы также можете найти решение путем сравнения для каждой строки start_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 
+0

Это работало @ Emil Moise. Спасибо –

+0

Вместо того, чтобы использовать подзапрос, чтобы найти предыдущую дату окончания, вы могли бы просто использовать аналитический запрос LAG(). – Boneist

+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 

ПРИМЕЧАНИЕ

С пункт только для построения выборочных данных для демонстрации , потому что вы не предоставили создавать и вставлять заявления. На самом деле вам нужно использовать свой собственный table_name вместо sample_data.

+0

У меня есть таблица с реестрами сотрудников 13k с эффективной датой начала и конечной датой, как указано выше ... Вышеупомянутый сценарий, который я дал, должен будет рассмотреть только несколько дат в заявлении ..... Я хочу более общее решение –

+0

@ divya.trehan573 Я думаю, вы не знаете о WITH предложение, которое просто для сборки данных образца для демонстрации.На самом деле вам нужно использовать свой собственный стол. –

+0

Да .. но у меня уже есть таблица с эффективными_статьи_данных и end_date. И для одного сотрудника я должен сравнивать даты между этими двумя датами. –

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 для генерации выборочных данных. Вам не нужен этот подзапрос, поскольку у вас уже есть таблица «abc».

+0

Спасибо @Boneist –

Смежные вопросы