Комбинирование запросов
Операторы множеств UNION
, INTERSECT
и EXCEPT
позволяют объединять результаты нескольких SELECT-запросов в один результирующий набор.
Кроме того, UNION
используется в рекурсивных CTE для объединения нерекурсивной и рекурсивной частей в итоговый результирующий набор.
Обзор синтаксиса
Операторы UNION
, INTERSECT
и EXCEPT
имеют схожий синтаксис:
<query1> UNION [ALL] <query2>
<query1> INTERSECT [ALL] <query2>
<query1> EXCEPT [ALL] <query2>
<query1>
и <query2>
— это запросы, результаты которых объединяются оператором.
Каждый запрос должен возвращать одинаковое количество столбцов с совместимыми типами данных.
Узнайте подробнее в статье UNION, CASE, and Related Constructs документации PostgreSQL.
Операторы множеств работают следующим образом:
-
UNION
— объединяет строки из<query1>
и<query2>
, удаляя дубликаты (аналогичноDISTINCT
). -
INTERSECT
— возвращает только те строки, которые присутствуют одновременно в<query1>
и<query2>
. -
EXCEPT
— возвращает строки из<query1>
, которых нет в<query2>
.
По умолчанию эти операторы удаляют дублирующиеся строки.
Чтобы сохранить дубликаты, используйте ключевое слово ALL
(например, UNION ALL
).
По умолчанию для UNION
, INTERSECT
и EXCEPT
дублирующиеся строки удаляются, хотя для SELECT
по умолчанию применяется ALL
.
Предварительные требования
Для выполнения команд, описанных в следующих разделах, подключитесь к мастер-хосту Greengage DB с помощью psql
, как описано в статье Подключение к Greengage DB с использованием psql.
Создайте новую базу данных и подключитесь к ней:
CREATE DATABASE marketplace;
\c marketplace
Затем создайте три таблицы и заполните их данными:
CREATE TABLE warehouse1_products
(
id INT,
name VARCHAR(100),
category VARCHAR(50)
)
WITH (appendoptimized = true)
DISTRIBUTED BY (id);
CREATE TABLE warehouse2_products
(
id INT,
name VARCHAR(100),
category VARCHAR(50)
)
WITH (appendoptimized = true)
DISTRIBUTED BY (id);
CREATE TABLE warehouse3_products
(
id INT,
name VARCHAR(100),
category VARCHAR(50)
)
WITH (appendoptimized = true)
DISTRIBUTED BY (id);
INSERT INTO warehouse1_products (id, name, category)
VALUES (1, 'Wireless mouse', 'Electronics'),
(2, 'Bluetooth speaker', 'Electronics'),
(3, 'Coffee maker', 'Home appliances'),
(4, 'Desk lamp', 'Home appliances');
INSERT INTO warehouse2_products (id, name, category)
VALUES (3, 'Coffee maker', 'Home appliances'),
(4, 'Desk lamp', 'Home appliances'),
(5, 'Smartphone', 'Electronics');
INSERT INTO warehouse3_products (id, name, category)
VALUES (1, 'Wireless mouse', 'Electronics'),
(2, 'Bluetooth speaker', 'Electronics'),
(5, 'Smartphone', 'Electronics'),
(6, 'Wireless headphones', 'Electronics');
Примеры использования
UNION
Этот запрос использует оператор UNION
для объединения товаров из двух таблиц в единый список, удаляя повторяющиеся строки:
SELECT id, name
FROM warehouse1_products
UNION
SELECT id, name
FROM warehouse2_products;
Результат выглядит так:
id | name ----+------------------- 1 | Wireless mouse 5 | Smartphone 2 | Bluetooth speaker 3 | Coffee maker 4 | Desk lamp (5 rows)
Этот SQL-запрос использует UNION ALL
для объединения товаров из обеих таблиц в один список, включая все дубликаты:
SELECT id, name
FROM warehouse1_products
UNION ALL
SELECT id, name
FROM warehouse2_products;
Результат содержит дублирующиеся строки, например, Coffee maker
и Desk lamp
:
id | name ----+------------------- 1 | Wireless mouse 3 | Coffee maker 4 | Desk lamp 3 | Coffee maker 4 | Desk lamp 2 | Bluetooth speaker 5 | Smartphone (7 rows)
INTERSECT
Этот SQL-запрос использует INTERSECT
, чтобы получить только те товары, которые присутствуют в обеих таблицах:
SELECT id, name
FROM warehouse1_products
INTERSECT
SELECT id, name
FROM warehouse2_products;
Результат выглядит следующим образом:
id | name ----+-------------- 3 | Coffee maker 4 | Desk lamp (2 rows)
EXCEPT
Этот SQL-запрос использует EXCEPT
, чтобы получить товары, которые есть в warehouse1_products
, но отсутствуют в warehouse2_products
:
SELECT id, name
FROM warehouse1_products
EXCEPT
SELECT id, name
FROM warehouse2_products;
Результат выглядит следующим образом:
id | name ----+------------------- 1 | Wireless mouse 2 | Bluetooth speaker (2 rows)
Сочетание операторов множеств
Вы можете комбинировать несколько операторов множеств в одном запросе.
Этот запрос использует два оператора UNION
для объединения товаров из трех таблиц в единый список:
SELECT id, name
FROM warehouse1_products
UNION
SELECT id, name
FROM warehouse2_products
UNION
SELECT id, name
FROM warehouse3_products;
id | name ----+--------------------- 3 | Coffee maker 4 | Desk lamp 5 | Smartphone 6 | Wireless headphones 2 | Bluetooth speaker 1 | Wireless mouse (6 rows)
Этот запрос сначала объединяет товары из warehouse1_products
и warehouse2_products
с помощью UNION
, а затем исключает товары из warehouse3_products
с помощью EXCEPT
:
SELECT id, name
FROM warehouse1_products
UNION
SELECT id, name
FROM warehouse2_products
EXCEPT
SELECT id, name
FROM warehouse3_products;
id | name ----+-------------- 3 | Coffee maker 4 | Desk lamp (2 rows)
Этот SQL-запрос сначала находит общие строки в warehouse2_products
и warehouse3_products
с помощью INTERSECT
, а затем добавляет к ним строки из warehouse1_products
при помощи UNION
:
SELECT id, name
FROM warehouse1_products
UNION
SELECT id, name
FROM warehouse2_products
INTERSECT
SELECT id, name
FROM warehouse3_products;
id | name ----+------------------- 3 | Coffee maker 4 | Desk lamp 1 | Wireless mouse 2 | Bluetooth speaker 5 | Smartphone (5 rows)
Обратите внимание, что INTERSECT
имеет более высокий приоритет, чем UNION
и EXCEPT
.
Порядок вычисления
Круглые скобки определяют порядок, в котором выполняются операции над множествами.
Без скобок UNION
и EXCEPT
обрабатываются слева направо.
INTERSECT
имеет более высокий приоритет, чем UNION
и EXCEPT
.
Следующие SQL-запросы эквивалентны:
SELECT id, name
FROM warehouse1_products
UNION
SELECT id, name
FROM warehouse2_products
INTERSECT
SELECT id, name
FROM warehouse3_products;
SELECT id, name
FROM warehouse1_products
UNION
(SELECT id, name
FROM warehouse2_products
INTERSECT
SELECT id, name
FROM warehouse3_products);
Добавьте скобки, чтобы гарантировать выполнение операции UNION
перед INTERSECT
:
(SELECT id, name
FROM warehouse1_products
UNION
SELECT id, name
FROM warehouse2_products)
INTERSECT
SELECT id, name
FROM warehouse3_products;
Применение модификаторов к операциям над множествами
Если нужно добавить модификаторы (например, LIMIT
) к отдельным запросам внутри операции объединения, заключайте такие запросы в скобки.
Без скобок может возникнуть ошибка или модификатор применится ко всему объединенному результату, а не к отдельному запросу.
Этот SQL-запрос объединяет все товары из warehouse1_products
и warehouse2_products
с помощью UNION ALL
, а затем ограничивает общий результат тремя строками:
(SELECT id, name
FROM warehouse1_products
UNION ALL
SELECT id, name
FROM warehouse2_products)
LIMIT 3;
id | name ----+---------------- 1 | Wireless mouse 3 | Coffee maker 4 | Desk lamp (3 rows)
Этот запрос сначала выбирает три строки из warehouse1_products
, а затем добавляет все строки из warehouse2_products
с помощью UNION ALL
:
(SELECT id, name
FROM warehouse1_products
LIMIT 3)
UNION ALL
SELECT id, name
FROM warehouse2_products;
id | name ----+------------------- 3 | Coffee maker 4 | Desk lamp 2 | Bluetooth speaker 5 | Smartphone 3 | Coffee maker 4 | Desk lamp (6 rows)