Pregunta

Hola, tengo los siguientes datos en la tabla:

ID ----- startDate ---- endDate
    5549 01-05-2008 4712-12-31
     5567 2008-04-17 2008-04-30 1
    5567 2008-05-01 2008-07-31 1
    5567 2008-09-01 4712-12-31 2

    5569 2008-05-01 2008-08-31
    5569 01-09-2008 4712-12-31
    5589 2008-04-18 2008-04-30
    5589 2008-05-01 4712-12-31
    5667 2008-05-01 4712-12-31
    5828 2008-06-03 4712-12-31
    5867 2008-06-03 4712-12-31
    6167 2008-11-01 4712-12-31
    6207 2008-07-01 4712-12-31
    6228 2008-07-01 4712-12-31
    6267 2008-07-14 4712-12-31

Estoy buscando la forma de agrupar los intervalos de tiempo continuos para que regrese cada ID:

ID, min (fecha de inicio), max (endDate),

tener algo como esto como resultado de la ID en negrita 5567

5567 2008-04-17 2008-07-31
5567 2008-09-01 4712-12-31

PL / SQL también es una opción aquí :)

Gracias,

¿Fue útil?

Solución

Creo que esto hará lo que necesitas: (tenga en cuenta que probablemente se confundirá con rangos superpuestos; no sé si son posibles en su conjunto de datos)

select id, min(start_date) period_start, max(end_date) period_end
from
(
select 
    id, start_date, end_date,
    max(contig) over (partition by id order by end_date) contiguous_group
from
(
select 
    id, start_date, end_date,
    case 
        when lag(end_date) over (partition by id order by end_date) != start_date-1 or row_number() over (partition by id order by end_date)=1 
            then row_number() over (partition by id order by end_date) else null end contig
from t2
)
)
group by id, contiguous_group
order by id, period_start
/

Aquí están los datos de prueba que utilicé, basados ??en los suyos con un par de entradas adicionales:

create table t2 (id number, start_date date, end_date date);

insert into t2(id, start_date, end_date)values(5549, to_date('2008-05-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5567, to_date('2008-04-17', 'yyyy-mm-dd'), to_date('2008-04-30', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5567, to_date('2008-05-01', 'yyyy-mm-dd'), to_date('2008-07-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5567, to_date('2008-08-01', 'yyyy-mm-dd'), to_date('2008-08-14', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5567, to_date('2009-09-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5567, to_date('2008-11-17', 'yyyy-mm-dd'), to_date('2008-12-13', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5567, to_date('2008-12-14', 'yyyy-mm-dd'), to_date('2008-12-24', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5569, to_date('2008-05-01', 'yyyy-mm-dd'), to_date('2008-08-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5569, to_date('2008-09-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5589, to_date('2008-04-18', 'yyyy-mm-dd'), to_date('2008-04-30', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5589, to_date('2008-05-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5667, to_date('2008-05-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5828, to_date('2008-06-03', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(5867, to_date('2008-06-03', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(6167, to_date('2008-11-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(6207, to_date('2008-07-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(6228, to_date('2008-07-01', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));
insert into t2(id, start_date, end_date)values(6267, to_date('2008-07-14', 'yyyy-mm-dd'), to_date('4712-12-31', 'yyyy-mm-dd'));

commit;

Otros consejos

Podría hacer esto con funciones analíticas como esta:

with d as
( select id, start_date, end_date
  ,      case when start_date = prev_end+1 
              then 'cont' else 'new' end start_status
  ,      case when end_date = next_start-1
              then 'cont' else 'new' end end_stat
  from
  (
  select id, start_date, end_date
  ,      lag(end_date) over (partition by id order by start_date) prev_end
  ,      lead(start_date) over (partition by id order by start_date) next_start
  from t1
  order by id, start_date
  )
)
select starts.id, starts.start_date, ends.end_date
from
( select id, start_date, row_number() over (order by id, start_date) rn
  from   d
  where  start_status='new'
) starts,
( select id, end_date, row_number() over (order by id, start_date) rn
  from   d
  where  end_status='new'
) ends
where starts.rn = ends.rn

Obtengo este resultado con sus datos:

        ID START_DATE END_DATE
---------- ---------- ----------
      5549 2008-05-01 4712-12-31
      5567 2008-04-17 2008-07-31
      5567 2008-09-01 4712-12-31
      5569 2008-05-01 4712-12-31
      5589 2008-04-18 4712-12-31
      5667 2008-05-01 4712-12-31
      5828 2008-06-03 4712-12-31
      5867 2008-06-03 4712-12-31
      6167 2008-11-01 4712-12-31
      6207 2008-07-01 4712-12-31
      6228 2008-07-01 4712-12-31
      6267 2008-07-14 4712-12-31

12 rows selected.

Cómo funciona:

  1. La cláusula WITH genera una vista D de los datos donde a cada fila se le asigna un " estado de inicio " y un " estado final " ;, cada uno de los cuales es 'nuevo' o 'cont' para indicar si es continuo con la fila anterior / siguiente o no.
  2. Vistas en línea " comienza " y "termina" extraiga solo las filas que tienen un " nuevo " estado inicial / final respectivamente, con un número de fila para unirlos.
  3. La " consulta principal " luego selecciona entre estas 2 vistas y se une en la columna de número de fila.

deberá escribir una lógica de muestra de bloque PL / SQL como se muestra a continuación;

Create or Replace someproc
Declare
    Cursore someCur AS
    Select * from someTable
    Order by ID,StartDate

    IDVar as Varchar(10)
    MinDate as DATE
    MaxDate as DATE

Begin
    Open someCur
    Fetch ID,StartDate,EndDate into IDVar,MinDate,MaxDate
    While SomeCur%NOTFOUND
    LOOP
        Fetch ID,StartDate,EndDate into TempID,TempStartDate,TempEndDate
        if IDVar <> TempID then
            -- output into your required structure values: IDVar,MinDate,MaxDate
            IDVar = TempID
            MinDate = TempStartDate
            MaxDate = TempEndDate
            Exit Loop
        ELSE IF
            MaxDate+1 >= TempStartDate THEN
            MaxDate = TempEndDate
        END IF
    End LOOP

No estoy cerca de una instancia para probar, pero ¿lo has intentado?

SELECT
 ID, 
 startDate,
 endDate
FROM
 myTable
WHERE
 (ID, startDate) in 
 (SELECT
   ID, 
   min(startDate) 
  FROM
   myTable
  GROUP BY
   ID
  )

  or 

 (ID, endDate) in 
 (SELECT
   ID, 
   max(endDate) 
  FROM
   myTable
  GROUP BY
   ID
  )

Esto debería proporcionarle todas las primeras startDate s, y las últimas endDate s para cada ID. Continuo o no.

WITH
  laik_test AS -- sample data
(select 1001 id, date'2012-01-03' start_date, date'2012-06-29' end_date from dual union
 select 1001 id, date'2012-03-03' start_date, date'2012-08-29' end_date from dual union
 select 1002 id, date'2012-06-03' start_date, date'2012-11-29' end_date from dual union
 select 1001 id, date'2012-09-03' start_date, date'2013-02-20' end_date from dual union
 select 1001 id, date'2013-02-08' start_date, date'2013-04-29' end_date from dual union
 select 1002 id, date'2012-11-03' start_date, date'2012-12-29' end_date from dual union
 select 1002 id, date'2012-12-23' start_date, date'2013-09-29' end_date from dual union
 select 1002 id, date'2013-08-03' start_date, date'2015-06-29' end_date from dual union
 select 1001 id, date'2013-04-13' start_date, date'2013-09-29' end_date from dual union
 select 1001 id, date'2013-07-03' start_date, date'2014-06-29' end_date from dual union
 select 1003 id, date'2012-12-23' start_date, date'2013-09-29' end_date from dual union
 select 1001 id, date'2013-07-03' start_date, date'2014-06-29' end_date from dual union
 select 1003 id, date'2012-12-23' start_date, date'2013-09-29' end_date from dual union
 select 1003 id, date'2013-09-30' start_date, date'2014-06-29' end_date from dual union
 select 1003 id, date'2013-12-30' start_date, date'2014-03-11' end_date from dual union
 select 1003 id, date'2014-06-29' start_date, date'2015-09-29' end_date from dual )
, matrica AS
(  select id, start_date, end_date
        , lead(start_date) over (partition by id order by start_date, end_date) start_date_next
        , lag(end_date) over (partition by id order by start_date, end_date) end_date_prev
  from laik_test m
 where not exists (select * 
                     from laik_test n
                    where m.id = n.id
                      and m.start_date > n.start_date and m.end_date < n.end_date))
, matrica2 AS
(select id, end_date
  from matrica m
 where start_date_next is null OR start_date_next > end_date + 1)
, matrica3 AS
(select id, start_date
  from matrica m
 where end_date_prev is null OR end_date_prev < start_date - 1)
, matrica4 AS
(select m2.id, m3.start_date, m2.end_date
  from matrica2 m2, matrica3 m3
 where m2.id=m3.id and m3.start_date < m2.end_date)
select id, start_date, end_date
  from matrica4 m
 where not exists (select * from matrica4 n
                    where m.id = n.id
                      and (   (n.start_date = m.start_date and m.end_date > n.end_date)
                           OR (n.end_date = m.end_date and m.start_date < n.start_date)
                          ));

Resultados es:

ID   | start_date | end_date
1001 | 2012-01-03 | 2012-08-29
1001 | 2012-09-03 | 2014-06-29
1002 | 2012-06-03 | 2015-06-29
1003 | 2012-12-23 | 2015-09-29

He estado tratando de hacer para la superposición de rangos, pero tengo algunas dificultades con estos datos:

     INSERT INTO zzz_scrap_dates (id,effdate,termdate)

SELECT id,effdate,termdate from (
SELECT '1'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '1'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2010-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '1'id ,To_Date('2005-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '1'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '1'id ,To_Date('1999-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
union
SELECT '2'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '2'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2010-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '2'id ,To_Date('2005-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '2'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '2'id ,To_Date('1999-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
union
SELECT '3'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '3'id ,To_Date('1998-01-01','YYYY-MM-DD')effdate,To_Date('1999-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '3'id ,To_Date('1005-01-01','YYYY-MM-DD')effdate,To_Date('1197-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '3'id ,To_Date('2000-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
UNION
SELECT '3'id ,To_Date('1197-01-01','YYYY-MM-DD')effdate,To_Date('2020-01-31','YYYY-MM-DD')termdate FROM dual
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top