By using db<>fiddle, you agree to license everything you submit by Creative Commons CC0.
CREATE TABLE table_name (ID, Start_Date, End_Date) AS
SELECT '001', DATE '2005-01-01', DATE '2006-01-01' FROM DUAL UNION ALL
SELECT '001', DATE '2005-01-01', DATE '2007-01-01' FROM DUAL UNION ALL
SELECT '001', DATE '2008-01-01', DATE '2008-06-01' FROM DUAL UNION ALL
SELECT '001', DATE '2008-04-01', DATE '2008-12-01' FROM DUAL UNION ALL
SELECT '001', DATE '2010-01-01', DATE '2010-05-01' FROM DUAL UNION ALL
SELECT '001', DATE '2010-04-01', DATE '2010-12-01' FROM DUAL UNION ALL
SELECT '001', DATE '2010-11-01', DATE '2012-01-01' FROM DUAL UNION ALL
SELECT '002', DATE '2010-11-01', DATE '2010-11-30' FROM DUAL UNION ALL
SELECT '002', DATE '2010-11-02', DATE '2010-11-09' FROM DUAL UNION ALL
SELECT '002', DATE '2010-11-11', DATE '2010-11-20' FROM DUAL UNION ALL
SELECT '002', DATE '2010-11-24', DATE '2010-12-02' FROM DUAL UNION ALL
SELECT '002', DATE '2010-12-05', DATE '2010-12-06' FROM DUAL UNION ALL
SELECT '002', DATE '2010-12-06', DATE '2010-12-08' FROM DUAL;
13 rows affected
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
SELECT *
FROM table_name
MATCH_RECOGNIZE(
PARTITION BY id
ORDER BY start_date
MEASURES
FIRST(start_date) AS start_date,
MAX(end_date) AS end_date
ONE ROW PER MATCH
PATTERN (overlapping_ranges* last_range)
DEFINE overlapping_ranges AS NEXT(start_date) <= MAX(end_date)
)
ID | START_DATE | END_DATE |
---|---|---|
001 | 2005-01-01 00:00:00 | 2007-01-01 00:00:00 |
001 | 2008-01-01 00:00:00 | 2008-12-01 00:00:00 |
001 | 2010-01-01 00:00:00 | 2012-01-01 00:00:00 |
002 | 2010-11-01 00:00:00 | 2010-12-02 00:00:00 |
002 | 2010-12-05 00:00:00 | 2010-12-08 00:00:00 |
SELECT id,
start_date,
end_date
FROM (
SELECT id,
dt,
SUM(cnt) OVER (PARTITION BY id ORDER BY dt) AS grp,
cnt
FROM (
SELECT ID,
dt,
SUM(type) OVER (PARTITION BY id ORDER BY dt ASC, type DESC, ROWNUM) * type AS cnt
FROM table_name
UNPIVOT (dt FOR type IN (start_date AS 1, end_date AS -1))
)
WHERE cnt IN (1,0)
)
PIVOT (MAX(dt) FOR cnt IN (1 AS start_date, 0 AS end_date))
ID | START_DATE | END_DATE |
---|---|---|
001 | 2005-01-01 00:00:00 | 2007-01-01 00:00:00 |
001 | 2008-01-01 00:00:00 | 2008-12-01 00:00:00 |
001 | 2010-01-01 00:00:00 | 2012-01-01 00:00:00 |
002 | 2010-11-01 00:00:00 | 2010-12-02 00:00:00 |
002 | 2010-12-05 00:00:00 | 2010-12-08 00:00:00 |
SELECT id,
MAX(CASE cnt WHEN 1 THEN dt END) AS start_date,
MAX(CASE cnt WHEN 0 THEN dt END) AS end_date
FROM (
SELECT id,
dt,
SUM(cnt) OVER (PARTITION BY id ORDER BY dt) AS grp,
cnt
FROM (
SELECT ID,
dt,
SUM(type) OVER (PARTITION BY id ORDER BY dt, rn) * type AS cnt
FROM (
SELECT r.*,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY dt ASC, type DESC) AS rn
FROM (
SELECT id, 1 AS type, start_date AS dt FROM table_name
UNION ALL
SELECT id, -1 AS type, end_date AS dt FROM table_name
) r
) p
) s
WHERE cnt IN (1,0)
) t
GROUP BY id, grp
ID | START_DATE | END_DATE |
---|---|---|
001 | 2005-01-01 00:00:00 | 2007-01-01 00:00:00 |
001 | 2008-01-01 00:00:00 | 2008-12-01 00:00:00 |
001 | 2010-01-01 00:00:00 | 2012-01-01 00:00:00 |
002 | 2010-11-01 00:00:00 | 2010-12-02 00:00:00 |
002 | 2010-12-05 00:00:00 | 2010-12-08 00:00:00 |
SELECT id,
MIN(start_date) AS start_date,
MAX(end_Date) AS end_date
FROM (
SELECT t.*,
SUM(CASE WHEN start_date <= prev_max THEN 0 ELSE 1 END)
OVER (PARTITION BY id ORDER BY start_date) AS grp
FROM (
SELECT t.*,
MAX(end_date) OVER (
PARTITION BY id ORDER BY start_date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
) AS prev_max
FROM table_name t
) t
) t
GROUP BY id, grp
ID | START_DATE | END_DATE |
---|---|---|
001 | 2005-01-01 00:00:00 | 2007-01-01 00:00:00 |
001 | 2008-01-01 00:00:00 | 2008-12-01 00:00:00 |
001 | 2010-01-01 00:00:00 | 2012-01-01 00:00:00 |
002 | 2010-11-01 00:00:00 | 2010-12-02 00:00:00 |
002 | 2010-12-05 00:00:00 | 2010-12-08 00:00:00 |