Комбинирование запросов (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);
Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней