How can we find the between the overlap lap b/w the dates . overlap means when start date and end date are within same range for below example row 1 has no over lap. Row 2to 5 can be considered as one set of over lap as there start date and end are over lap with themselves Row 6 & 7 can be considered as one set of over lap for eg. row 6 & 7 –> start date of row 7 is in same range with respect to end date of row 6 so it becomes an overlap
Once overlap is found then and need to find out min(start date) and max(end date) and want to assign a unique id to each overlap and in the S.NO column should show which rows are overlapped.
Advertisement
Answer
Based on this answer (which contains a detailed explanation of the query), you can change the final part to generate groups of overlapping rows and then aggregate using LISTAGG
to get the delimited sno
values:
SELECT id,
MIN( dt ) AS start_date,
MAX( dt ) AS end_date,
LISTAGG( CASE value WHEN 1 THEN sno END, ',' )
WITHIN GROUP ( ORDER BY dt ) AS snos
FROM (
SELECT sno,
id,
dt,
value,
SUM( start_end ) OVER ( ORDER BY dt ASC, value DESC )
AS grp
FROM (
SELECT sno,
id,
dt,
value,
CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 1
WHEN 0 THEN 0
ELSE NULL
END AS start_end
FROM table_name
UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
)
)
GROUP BY id, grp;
Which, for the sample data:
CREATE TABLE table_name ( sno, id, start_date, end_date ) AS
SELECT 1, 1, DATE '2020-10-11', DATE '2020-10-11' FROM DUAL UNION ALL
SELECT 2, 1, DATE '2020-11-04', DATE '2020-12-11' FROM DUAL UNION ALL
SELECT 3, 1, DATE '2020-11-05', DATE '2020-11-10' FROM DUAL UNION ALL
SELECT 4, 1, DATE '2020-11-06', DATE '2020-11-10' FROM DUAL UNION ALL
SELECT 5, 1, DATE '2020-11-20', DATE '2020-12-20' FROM DUAL UNION ALL
SELECT 6, 1, DATE '2021-01-01', DATE '2021-01-20' FROM DUAL UNION ALL
SELECT 7, 1, DATE '2021-01-01', DATE '2021-03-25' FROM DUAL;
Outputs:
ID | START_DATE | END_DATE | SNOS -: | :------------------ | :------------------ | :------ 1 | 2020-10-11 00:00:00 | 2020-10-11 00:00:00 | 1 1 | 2020-11-04 00:00:00 | 2020-12-20 00:00:00 | 2,3,4,5 1 | 2021-01-01 00:00:00 | 2021-03-25 00:00:00 | 6,7
db<>fiddle here
From Oracle 12c you can use MATCH_RECOGNIZE
for a much simpler query:
SELECT id,
MIN( start_date ) AS start_date,
MAX( end_date ) AS end_date,
LISTAGG( sno, ',' ) WITHIN GROUP ( ORDER BY start_date ASC, END_DATE ASC )
AS snos
FROM table_name
MATCH_RECOGNIZE (
PARTITION BY id
ORDER BY start_date ASC, end_date ASC
MEASURES MATCH_NUMBER() AS grp
ALL ROWS PER MATCH
PATTERN ( OVERLAPPING_DATES* LAST_DATE )
DEFINE OVERLAPPING_DATES AS NEXT( start_date ) <= MAX( end_date )
)
GROUP BY id, grp
db<>fiddle here