27.02.2016 0 min to read

Выборка разности двух множеств и дополнительных полей оставшихся записей

Category : Статьи

В БД Oracle существует 4 операции с множествами выбранных данных:

  • union – объединение множеств записей, полученных в результате двух выборок
  • union all – добавление всех записей второй выборки к результату первой выборки (отличие от union – дублирующие записи не исключаются)
  • intersect – пересечение множеств записей, полученных в результате двух выборок
  • minus – разность множеств записей, т.е. записи из первой выборки, отсутствующие во второй

Все эти операции в некоторых случаях позволяют существенно уменьшить время выполнения запроса и используются достаточно активно. Часто встречается задача, которую условно можно описать следующим образом: выбрать все записи главной таблицы (со всеми имеющимися полями), на которые нет ссылок из подчиненных таблиц. Очень простой и распространенный случай. Допустим, есть 2 таблицы: T1 и Т2, причем T2ссылается на T1 двумя полями.

create table T1 (
f1 number not null,
f2 number not null,
f3 date,
f4 varchar2(32),
f5 number,
constraint PK_T1 primary key (f1, f2)
);

create table T2 (
f1 number,
f2 number,
constraint FK_T1 foreign key (f1, f2) references T1 (f1, f2)
);

 

Для решения задачи берем 2 выборки (из T1 и из Т2), вычитаем одну из другой (minus), а потом заново из первой таблицы T1 отбираем записи, попавшие в разность:

select f1, f2, f3, f4, f5
from
T1,
(
select f1, f2 from T1
minus
select f1, f2 from T2
) T
where
T1.f1 = T.f1 and
T1.f2 = T.f2

 

В таком решении есть недостаток – двойное обращение к одному и тому же источнику (в данном случае таблице T1). Если в роли источника будет выступать представление или сложный запрос, это может существенно снизить скорость получения результата. Тогда возникает другой вариант решения, где к каждому источнику идет только одно обращение:

select
f1, f2,
max(f3) f3, max(f4) f4, max(f5) f5
from (
select f1, f2, f3, f4, f5 from T1
union all
select f1, f2, null, null, null from T2
)
group by f1, f2
having count(*) = 1

 

Добавляем все записи из второй таблицы к записям первой таблицы, а потом группируем их по ключам и оставляем только те группы, в которых оказалась только одна запись (это может быть только запись главной таблицы). Параллельно, ко всем требующимся дополнительным полям применяем групповую функцию.

Tags: ,