Комбинирование запросов (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);