To jest gorączkowe jak wszystko, ale powinno zapewnić ci to, czego potrzebujesz:
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
Najbardziej wewnętrzne zapytanie grupuje okresy w nakładające się grupy, w razie potrzeby rozciągając datę_końcową. Data_końcowa wygina się, ponieważ założyłem, że mogą istnieć okresy całkowicie objęte poprzednią.
Następne zapytanie opakowujące wyodrębnia pełny zakres z każdej grupy.
Zewnętrzne zapytanie sumuje pełne różnice miesięczne dla każdej grupy. Wszystkie różnice grupowe są zaokrąglane w dół do najbliższego pełnego miesiąca o PERIOD_DIFF.
Niestety nie mogłem tego przetestować, ponieważ SQLFiddle na mnie umarł.