Комбинирование запросов (UNION, INTERSECT, EXCEPT)
Вы можете использовать операторы множеств UNION, INTERSECT и EXCEPT для объединения результатов двух запросов. Эти операторы имеют следующий синтаксис:
<запрос1> UNION [ALL] <запрос2>
<запрос1> INTERSECT [ALL] <запрос2>
<запрос1> EXCEPT [ALL] <запрос2>
Где:
-
<запрос1>и<запрос2>— запросы для объединения. Запросы должны быть совместимыми для объединения, т.е. возвращать одинаковое количество столбцов. Соответствующие столбцы должны иметь совместимые типы данных, как описано в следующей статье: UNION. -
UNIONдобавляет результат второго запроса к результату первого запроса. Порядок, в которомUNIONвозвращает строки, не определен. -
INTERSECTвозвращает все строки, которые есть как в результате первого запроса, так и в результате второго запроса. -
EXCEPTвозвращает все строки, которые включены в результат первого запроса, но не входят в результат второго запроса. -
ALLуказывает, что в результат должны быть включены повторяющиеся строки. Если запрос не содержит модификатораALL, операторыUNION,INTERSECTиEXCEPTисключают повторяющиеся строки из результата.
Чтобы посмотреть, как работают операторы множеств, создадим три таблицы:
CREATE TABLE book_store1(
id INT PRIMARY KEY,
title VARCHAR (100)
);
CREATE TABLE book_store2(
id INT PRIMARY KEY,
title VARCHAR (100)
);
CREATE TABLE book_store3(
id INT PRIMARY KEY,
title VARCHAR (100)
);
INSERT INTO book_store1 (id, title) VALUES
(1, 'Hyperion'),
(2, '1984'),
(3, 'War and Peace'),
(4, 'The Time Machine');
INSERT INTO book_store2 (id, title) VALUES
(3, 'War and Peace'),
(4, 'The Time Machine'),
(5, 'Mrs. Dalloway' );
INSERT INTO book_store3 (id, title) VALUES
(1, 'Hyperion'),
(2, '1984'),
(5, 'Mrs. Dalloway' );
Пример UNION
Следующий запрос использует UNION для объединения таблиц book_store1 и book_store2:
SELECT * from book_store1 UNION SELECT * from book_store2;
Результат:
id | title ----+------------------ 5 | Mrs. Dalloway 4 | The Time Machine 2 | 1984 3 | War and Peace 1 | Hyperion
Добавим модификатор ALL и сравним результаты:
SELECT * from book_store1 UNION ALL SELECT * from book_store2;
Результат содержит повторяющиеся строки:
id | title ----+------------------ 1 | Hyperion 2 | 1984 3 | War and Peace 4 | The Time Machine 3 | War and Peace 4 | The Time Machine 5 | Mrs. Dalloway
Пример INTERSECT
Следующий запрос использует INTERSECT для возврата всех строк, которые есть в обеих таблицах: и в book_store1, и в book_store2:
SELECT * from book_store1 INTERSECT SELECT * from book_store2;
Результат:
id | title ----+------------------ 4 | The Time Machine 3 | War and Peace
Пример EXCEPT
Запрос ниже использует EXCEPT, чтобы вернуть все строки, которые есть в таблице book_store1, но отсутствуют в book_store2.
SELECT * from book_store1 EXCEPT SELECT * from book_store2;
Результат:
id | title ----+---------- 2 | 1984 1 | Hyperion
Сочетание операторов множеств
Вы можете комбинировать операторы множеств в одном запросе.
Например, следующий запрос сначала объединяет таблицы book_store1 и book_store2, а затем исключает из результата строки таблицы book_store3:
SELECT * from book_store1 UNION SELECT * from book_store2
EXCEPT SELECT * from book_store3;
Результат:
id | title ----+------------------ 4 | The Time Machine 3 | War and Peace
Круглые скобки определяют порядок применения операторов. Без круглых скобок UNION и EXCEPT выполняются слева направо.
Следующие выражения эквивалентны:
<запрос1> UNION <запрос2> EXCEPT <запрос3>
(<запрос1> UNION <запрос2>) EXCEPT <запрос3>
INTERSECT имеет более высокий приоритет, чем UNION и EXCEPT. Следующие выражения эквивалентны:
<запрос1> UNION <запрос2> INTERSECT <запрос3>
<запрос1> UNION (<запрос2> INTERSECT <запрос3>)
Выполним следующий запрос с INTERSECT:
SELECT * from book_store1 UNION SELECT * from book_store2
INTERSECT SELECT * from book_store3;
PostgreSQL сначала выполнит INTERSECT, его результат:
id | title ----+--------------- 5 | Mrs. Dalloway
После этого выполняется UNION, который объединяет результат, приведенный выше, со строками book_store1.
Результат:
id | title ----+------------------ 5 | Mrs. Dalloway 4 | The Time Machine 2 | 1984 3 | War and Peace 1 | Hyperion
Добавим скобки в запрос:
(SELECT * from book_store1 UNION SELECT * from book_store2)
INTERSECT SELECT * from book_store3;
PostgreSQL сначала выполнит UNION, его результат:
id | title ----+------------------ 5 | Mrs. Dalloway 4 | The Time Machine 2 | 1984 3 | War and Peace 1 | Hyperion
После этого INTERSECT возвращает все строки, которые есть как в результате выполнения UNION, так и в таблице book_store3.
Результат:
id | title ----+--------------- 2 | 1984 1 | Hyperion 5 | Mrs. Dalloway
Чтобы использовать дополнительные выражения во входных запросах, например LIMIT, заключите запросы в круглые скобки. Если добавить дополнительное выражение в запрос без круглых скобок, может возникнуть синтаксическая ошибка или выражение применится к выходным данным оператора множеств, а не к отдельному запросу. Например, следующий запрос выполнится без ошибок, но PostgreSQL применит LIMIT 10 к результату UNION:
SELECT a FROM b UNION SELECT x FROM y LIMIT 10;
Этот запрос эквивалентен следующему выражению:
(SELECT a FROM b UNION SELECT x FROM y) LIMIT 10;
Чтобы применить LIMIT ко второму запросу, заключите этот запрос в круглые скобки:
SELECT a FROM b UNION (SELECT x FROM y LIMIT 10);