Идея этого подхода состоит в том, чтобы разматывать обе таблицы, отслеживая, находятся ли числа в справочной таблице или исходной таблице. Это действительно громоздко, потому что смежные значения могут вызвать проблемы.
Идея состоит в том, чтобы сделать решение типа «промежутки и островки» вдоль обоих измерений, а затем сохранить только те значения, которые находятся в исходной таблице, а не во втором. Возможно, это можно было бы назвать «исключающими пробелами и островками».
Вот рабочая версия:
with vals as (
select min as x, 1 as inc, 0 as is_ref
from test_table
union all
select max + 1, -1 as inc, 0 as is_ref
from test_table
union all
select min as x, 0, 1 as is_ref
from reference_table
union all
select max + 1 as x, 0, -1 as is_ref
from reference_table
)
select min, max
from (select refgrp, incgrp, ref, inc2, min(x) as min, (lead(min(x), 1, max(x) + 1) over (order by min(x)) - 1) as max
from (select v.*,
row_number() over (order by x) - row_number() over (partition by ref order by x) as refgrp,
row_number() over (order by x) - row_number() over (partition by inc2 order by x) as incgrp
from (select v.*, sum(is_ref) over (order by x, inc) as ref,
sum(inc) over (order by x, inc) as inc2
from vals v
) v
) v
group by refgrp, incgrp, ref, inc2
) v
where ref = 0 and inc2 = 1 and min < max
order by min;
И здесь - это дБ <> скрипка.
Обратная задача получения перекрытий намного проще. Для этого может быть целесообразно «инвертировать» справочную таблицу.
select greatest(tt.min, rt.min), least(tt.max, rt.max)
from test_table tt join
reference_table rt
on tt.min < rt.max and tt.max > rt.min -- is there an overlap?