Ini sibuk seperti apa pun tetapi harus memberi Anda apa yang Anda butuhkan:
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
Kueri paling dalam mengelompokkan periode Anda dalam grup yang tumpang tindih yang merentangkan tanggal_akhir jika sesuai. Tanggal_akhir melentur karena saya berasumsi bahwa mungkin ada periode yang sepenuhnya tertutup oleh periode sebelumnya.
Kueri pembungkusan berikutnya mengekstrak rentang penuh dari setiap grup.
Kueri luar meringkas perbedaan bulan penuh untuk setiap grup. Semua perbedaan grup dibulatkan ke bawah ke bulan penuh terdekat dengan PERIOD_DIFF.
Sayangnya saya tidak dapat menguji ini karena SQLFiddle telah mati pada saya.