I have simple table with start_date
and end_date
columns in it. These date values may overlap
id start_date end_date
1 2011-0
If you need the total periods for a number of records including the overlaps, then simply sum the period differences per record:
SELECT SUM(PERIOD_DIFF( DATE_FORMAT(end_date, '%Y%m') , DATE_FORMAT(start_date, '%Y%m') )) AS total_periods
FROM table WHERE ...
This is hectic as anything but should get you what you need:
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
The inner-most query groups together your periods in overlapping groups stretching the end_date where appropriate. The end_date flexes as I assumed that there could be periods completely enclosed by the previous.
The next wrapping query extracts the full range from each group.
The outer query sums up the full month diffs for each group. All group diffs are rounded down to the nearest full month by PERIOD_DIFF.
Unfortunately I couldn't test this as SQLFiddle has died on me.
I did it my own way checking other answers here on Stackoverflow, it should work:
select sum(months)
from (select t.*,
@time := if(@sum = 0, 0, period_diff(date_format(start_date, '%Y%m'), date_format(@prevtime, '%Y%m'))) as months,
@prevtime := start_date,
@sum := @sum + isstart
from ((select start_date, 1 as isstart
from position t
) union all
(select end_date, -1
from position t
)
) t cross join
(select @sum := 0, @time := 0, @prevtime := 0) vars
order by 1, 2
) t