これは何よりも多忙ですが、必要なものが得られるはずです:
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
最も内側のクエリは、必要に応じてend_dateを拡張する重複するグループに期間をグループ化します。 end_dateは、前の期間で完全に囲まれた期間が存在する可能性があると想定したため、変更されます。
次のラッピングクエリは、各グループから全範囲を抽出します。
外側のクエリは、各グループの1か月の差異を合計します。すべてのグループ差異は、PERIOD_DIFFによって最も近い1か月に切り捨てられます。
残念ながら、SQLFiddleが死んでしまったため、これをテストできませんでした。