SQL Ergebnisse von kontinuierlichen Zeitintervallen der Gruppierung (Oracle SQL)
-
06-07-2019 - |
Frage
Hallo, ich habe folgende Daten in der Tabelle:
ID ----- ---- startdate endDate
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
Ich suche mich, um die kontinuierlichen Zeitintervall Gruppe für jede ID zurück:
ID, min (startdate), max (endDate)
so etwas wie dies in Folge haben, für die bolded ID 5567
5567 2008-04-17 2008-07-31
5567 2008-09-01 4712-12-31
PL / SQL ist auch eine Option hier:)
Danke,
Lösung
Ich denke, das zu tun, was Sie brauchen: (Beachten Sie, dass es wahrscheinlich durch überlappende Bereiche verwirren lassen, wissen nicht, ob sie in Ihrem Datensatz möglich sind)
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
/
Hier ist die Testdaten, die ich verwenden - auf Sich mit ein paar zusätzlichen Einträgen basieren:
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;
Andere Tipps
Sie können dies tun mit analytischen Funktionen wie folgt aus:
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
ich dieses Ergebnis mit Ihren Daten:
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.
Wie es funktioniert:
- Die WITH Klausel erzeugt eine Ansicht D der Daten, wobei jede Zeile ein „Startzustand“ zugeordnet ist, und ein „Ende-Status“, von denen jedes ‚neue‘ oder ‚cont‘ ist, um anzuzeigen, ob es mit dem vorherigen kontinuierlich ist / nächste Zeile oder nicht.
- In-line sieht „beginnt“ und „Enden“ nur die Zeilen herausziehen, die einen „neuen“ Start Status / Endstatus haben jeweils mit einer Zeilennummer, sie heiraten werden.
- Die „Hauptabfrage“ wählt dann aus diesen zwei Ansichten und schließt sich auf die Zeilennummer Spalte.
Sie werden wie unten ein PL / SQL-Block Probe Logik schreiben müssen;
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
Ich bin nicht in der Nähe von einer Instanz zu testen, aber haben Sie versucht;
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
)
Dies sollte Ihnen alle frühesten startDate
s und die neuesten endDate
s für jede ID. Kontinuierlich oder nicht.
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)
));
Ergebnisse sind:
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
Ich habe versucht, für überlappende Bereiche zu tun, aber einige Schwierigkeiten, Mit Hilfe dieser Daten:
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