Union dates: t1.begin, t1.end, t2.begin-1, t2.end+1. From such union create small periods using lead()
. Finally exclude rows with overlapping periods in table2:
select t.id, t.d1, t.d2 from (
select id, dt d1, lead(dt) over (partition by id order by dt) d2
from (
select id, d1 dt from table1 union select id, d2 from table1 union
select id, dateadd(day, -1, d1) d1 from table2 union
select id, dateadd(day, 1, d2) d2 from table2) u ) t
left join table2 a on a.id = t.id and a.d1 < t.d2 and t.d1 < a.d2
where a.id is null and t.d2 is not null
dbfiddle demo
Edit:
After testing it appears that above query does not handle one day periods required in the output properly. So instead of union
I used union all
in the inner query and then additional grouping of result:
select id, min(d1) d1, max(d2) d2
from (
select id, d1, d2, sum(mrk) over (partition by id order by d1, d2) grp
from (
select t.id, t.d1, t.d2,
case when lag(t.d2) over (partition by t.id order by t.d1, t.d2) = t.d1
then 0 else 1 end mrk
from (
select id, dt d1, lead(dt) over (partition by id order by dt) d2
from (
select id, d1 dt from #table1 union all select id, d2 from #table1 union all
select id, dateadd(day, -1, d1) d1 from #table2 union all
select id, dateadd(day, 1, d2) d2 from #table2) u ) t
left join #table2 a on a.id = t.id and a.d1 < t.d2 and t.d1 < a.d2
where a.id is null and t.d2 is not null) t) x
group by id, grp order by id, d1, d2
dbfiddle demo