Creo que una forma de hacerlo puede ser de la siguiente manera:
Hay que localizar los principios de bloque inicial y el ultimo final de bloque,
para lo cual debe de cumplir que en los principios de bloque, el campo `desde` no este contenido dentro de ningún otro bloque
y para los finales de bloque es el campo `hasta` el que no debe de estar contenido dentro de ningún bloque.
Una vez que tienes el principio de bloque, el final de bloque, será la menor fecha de todos los finales de bloque que sea mayor que la fecha del principio de bloque.
Con los datos que has puesto de ejemplo, creo que este código te puede funcionar:
Código SQL
[-]
-- localiza los principios de bloque independientes:
SELECT `ini`.id,
ini.desde,
( --
-- localiza el fin de bloque
-- que sera la fecha mas cercana al inicio de bloque
SELECT min(fin.hasta) AS hasta
FROM `fechas` fin
LEFT JOIN fechas ant
ON ant.aid <> fin.aid
AND ant.id = fin.id
AND fin.hasta BETWEEN ant.desde AND ant.hasta
WHERE ant.aid IS NULL
AND fin.id = ini.id
AND fin.`hasta` >= ini.hasta)
AS hasta
FROM `fechas` ini
LEFT JOIN fechas ant
ON ant.aid <> ini.aid
AND ant.id = ini.id
AND ini.desde BETWEEN ant.desde AND ant.hasta
WHERE ant.aid IS NULL
ORDER BY ini.id, ini.desde;