Oracle solution 2
WITH borders AS /*get all borders of interval*/
(SELECT DISTINCT DECODE(is_end, 0, range_start, range_end) AS border
,is_end
FROM ranges r,
(SELECT 0 AS is_end FROM dual UNION ALL
SELECT 1 AS is_end FROM dual)),
interv AS /*get all intervals*/
(SELECT border + is_end AS beg_int
,lead(border) over(ORDER BY border, is_end )
- lead(DECODE(is_end, 0, 1, 0)) over(ORDER BY border, is_end) AS end_int
FROM borders
ORDER BY 1)
SELECT i.beg_int
,i.end_int
,(SELECT MAX(r.range_val) keep (dense_rank FIRST ORDER BY r.range_end - r.range_start)
FROM ranges r
WHERE i.beg_int >= r.range_start AND i.end_int <= r.range_end) AS range_val
FROM interv i
WHERE beg_int <= end_int OR end_int IS NULL
ORDER BY i.beg_int;
Add solution without self join : EDIT: fixed defect.
WITH intervals AS
(SELECT DECODE(is_end, -1, range_val, NULL) AS range_val
,DECODE(is_end, -1, range_start, range_end) AS border
,is_end
,- (SUM(is_end) over(ORDER BY DECODE(is_end, -1, range_start, range_end), is_end, (range_end - range_start) * is_end)) AS poss
,(range_end - range_start) * is_end AS ord2
FROM ranges r
,(SELECT -1 AS is_end FROM dual UNION ALL
SELECT 1 AS is_end FROM dual)),
range_stack AS
(SELECT border + DECODE(is_end, 1, 1, 0) AS begin_int
,lead(border) over(ORDER BY border, is_end, ord2)
+ DECODE(lead(is_end) over(ORDER BY border, is_end, ord2), 1, 0, -1) AS end_int
,last_value(range_val ignore NULLS) over(PARTITION BY poss ORDER BY border, is_end, ord2) AS range_val
FROM intervals)
SELECT begin_int
,end_int
,range_val
FROM range_stack
WHERE end_int >= begin_int
OR end_int IS NULL;