Đây là bất cứ điều gì bận rộn nhưng sẽ giúp bạn có được những gì bạn cần:
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
Các truy vấn nội bộ nhất nhóm các khoảng thời gian của bạn lại với nhau thành các nhóm chồng chéo kéo dài ngày end_date nếu thích hợp. End_date linh hoạt khi tôi giả định rằng có thể có các khoảng thời gian hoàn toàn nằm trong khoảng thời gian trước đó.
Truy vấn gói tiếp theo trích xuất toàn bộ phạm vi từ mỗi nhóm.
Truy vấn bên ngoài tính tổng các tháng khác nhau cho mỗi nhóm. Tất cả sự khác biệt của nhóm được làm tròn xuống thành đầy tháng gần nhất theo PERIOD_DIFF.
Rất tiếc, tôi không thể kiểm tra điều này vì SQLFiddle đã chết đối với tôi.