Questo è frenetico come qualsiasi cosa, ma dovrebbe darti ciò di cui hai bisogno:
SELECT SUM(PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM a.end_date), EXTRACT(YEAR_MONTH FROM a.start_date))) months
FROM (
SELECT MIN(g.start_date) start_date, MAX(g.end_date) end_date
FROM (
SELECT @group_id := @group_id + (@end_date IS NULL OR o.start_date > @end_date) group_id,
start_date,
@end_date := DATE(CASE
WHEN (@end_date IS NULL OR o.start_date > @end_date) THEN o.end_date
ELSE GREATEST(o.end_date, @end_date)
END) end_date
FROM overlap o
JOIN (SELECT @group_id := 0, @end_date := NULL) init
ORDER BY o.start_date ASC
) g
GROUP BY g.group_id
) a
La query più interna raggruppa i tuoi periodi in gruppi sovrapposti estendendo la data_fine dove appropriato. La data_fine si flette poiché presumevo che potessero esserci periodi completamente racchiusi dal precedente.
La successiva query di wrapping estrae l'intero intervallo da ciascun gruppo.
La query esterna riassume le differenze mensili intere per ciascun gruppo. Tutte le differenze di gruppo vengono arrotondate per difetto al mese intero più vicino da PERIOD_DIFF.
Sfortunatamente non ho potuto testarlo poiché SQLFiddle è morto su di me.