Question

Bonjour, j'ai les données suivantes dans le tableau:

ID ----- date de début ---- date de fin
    5549 2008-05-01 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 2008-09-01 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

Je cherche un moyen de regrouper les intervalles de temps continus que chaque identifiant doit renvoyer:

ID, min (startDate), max (endDate),

avoir quelque chose comme ceci dans le résultat pour l'ID en gras 5567

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

PL / SQL est également une option ici:)

Merci,

Était-ce utile?

La solution

Je pense que cela fera ce dont vous avez besoin: (notez que des plages se chevaucheront probablement, ce qui entraînera probablement une certaine confusion.

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
/

Voici les données de test que j'ai utilisées - basées sur la vôtre avec quelques entrées supplémentaires:

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;

Autres conseils

Vous pouvez le faire avec des fonctions analytiques telles que:

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

Je reçois ce résultat avec vos données:

        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.

Comment ça marche:

  1. La clause WITH génère une vue D des données où un "état de démarrage" est affecté à chaque ligne. et un "état final", chacun étant "nouveau" ou "continu" pour indiquer s'il est continu ou non avec la rangée précédente / suivante.
  2. Vues en ligne " démarre " et " se termine " extraire uniquement les lignes qui ont un " nouveau " statut de départ / statut de fin, avec un numéro de ligne pour les épouser.
  3. La " requête principale " sélectionne ensuite à partir de ces 2 vues et se joint à la colonne du numéro de ligne.

vous devrez écrire un exemple de logique de bloc PL / SQL comme ci-dessous;

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

Je ne suis pas près d'une instance à tester, mais avez-vous essayé;

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
  )

Ceci devrait vous donner tous les startDate les plus anciens, ainsi que les endDate les plus récents pour chaque ID. Continu ou pas.

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)
                          ));

Le résultat est:

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

J'ai essayé de faire pour les gammes qui se chevauchent, mais j'ai eu quelques difficultés avec ces données:

     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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top