Aquí hay un método para resolver este problema. Cree una bandera que determine si un registro no solapamiento con el anterior. Este es el comienzo de un grupo. Luego tome la suma acumulada de esta bandera y úsela para agrupar:
select user_id, min(begin_at) as begin_at, max(end_at) as end_at
from (select s.*, sum(startflag) over (partition by user_id order by begin_at) as grp
from (select s.*,
(case when lag(end_at) over (partition by user_id order by begin_at) >= begin_at
then 0 else 1
end) as startflag
from slots s
) s
) s
group by user_id, grp;
Aquí es un violín SQL.