В БД 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
Добавляем все записи из второй таблицы к записям первой таблицы, а потом группируем их по ключам и оставляем только те группы, в которых оказалась только одна запись (это может быть только запись главной таблицы). Параллельно, ко всем требующимся дополнительным полям применяем групповую функцию.