Зарегистрируйтесь, чтобы продолжить обучение

Объединение запросов Множественные операции в SQL

В этом уроке мы разберем оператор UNION. Чтобы попрактиковаться, мы возьмем нашу базу данных. В ней есть две таблицы с информацией о студентах, которые записывались на курсы в 2022 и 2023 году:

  • course_members_2022
  • course_members_2023

Обе таблицы имеют одинаковую структуру:

  • Имя пользователя
  • Название курса
  • Дата записи на курс

Попробуем выяснить, кто записывался на курс по PHP в каждом году. Для этого выполним два запроса:

SELECT username FROM course_members_2022
WHERE coursename = 'PHP';
SELECT username FROM course_members_2023
WHERE coursename = 'PHP'

Выполнив эти запросы, мы получим две таблицы:

  • С четырьмя пользователями за 2022 год
  • С одним пользователем за 2023 год

php_course_memebers_22

username
Kendall50
Abelardo58
Elwyn17
Justin87

php_course_memebers_23

username
Leola.Ward

View on DB Fiddle

Оператор UNION

Теперь объединим результаты этих запросов. Воспользуемся оператором UNION, который объединяет два запроса в один:

SELECT username FROM course_members_2022
WHERE coursename = 'PHP'

UNION

SELECT username FROM course_members_2023
WHERE coursename = 'PHP';

В результате мы получим пять строк:

php_course_memebers

username
Elwyn17
Kendall50
Justin87
Abelardo58
Leola.Ward

View on DB Fiddle

union

Теперь попробуем объединить несколько запросов. Для этого укажем оператор UNION после каждого запроса:

SELECT username FROM course_members_2022
WHERE coursename = 'PHP'

UNION

SELECT username FROM course_members_2022
WHERE coursename = 'SQL'

UNION

SELECT username FROM course_members_2022
WHERE coursename = 'Javascript';

course_memebers_2022

username
Elwyn17
Kendall50
Curtis_Baumbach
Michaela11
Justin87
Abelardo58
Duncan3

View on DB Fiddle

Обратите внимание, что объединять можно далеко не все запросы. Следите, чтобы выполнялись два правила:

  • Во всех таблицах должно быть одинаковое количество столбцов
  • Во всех таблицах должны быть одинаковые типы данных

Одинаковое количество столбцов

Если мы хотим объединить два подзапроса, они должны работать с одинаковым количеством столбцов. Посмотрите на запрос ниже:

SELECT username, created_at FROM course_members_2022
WHERE coursename = 'PHP'

UNION

SELECT username FROM course_members_2023
WHERE coursename = 'PHP';

Этот запрос выполнить не получится, потому что есть разница в столбцах:

  • В первом подзапросе мы выводим два столбца — имя пользователя и дату записи
  • Во втором подзапросе мы выводим только один столбец — имя пользователя

Чтобы исправить эту проблему, подправим второй подзапрос. Нам нужно либо вывести поле created_at в качестве второго столбца, либо заполнить этот столбец значением NULL.

Этот запрос выведет поле created_at для обоих подзапросов:

SELECT
    username,
    created_at
FROM course_members_2022
WHERE coursename = 'PHP'

UNION

SELECT
    username,
    created_at
FROM course_members_2023
WHERE coursename = 'PHP';

php_course_memebers

username created_at
Leola.Ward 2023-01-06T01:52:34.914Z
Justin87 2022-06-22T01:45:38.476Z
Elwyn17 2022-06-21T10:52:36.105Z
Abelardo58 2022-06-18T04:52:36.764Z
Kendall50 2022-06-15T11:33:56.286Z

View on DB Fiddle

А этот — выведет во втором столбце значение NULL:

SELECT
    username,
    created_at
FROM course_members_2022
WHERE coursename = 'PHP'

UNION

SELECT
    username,
    NULL
FROM course_members_2023
WHERE coursename = 'PHP';

php_course_memebers

username created_at
Leola.Ward null
Justin87 2022-06-22T01:45:38.476Z
Elwyn17 2022-06-21T10:52:36.105Z
Abelardo58 2022-06-18T04:52:36.764Z
Kendall50 2022-06-15T11:33:56.286Z

View on DB Fiddle

Одинаковые типы данных

Чтобы могли объединять запросы, важно и второе правило — чтобы оба запроса работали с одинаковыми типами данных. Попробуем объединить два подзапроса:

  • В первом запросе укажем столбы username и created_at (текст и дата)
  • Во втором запросе укажем столбцы created_at и username (дата и текст, то есть в обратном порядке)

Столбцы в подзапросах работают с разными типами данных, поэтому такой запрос не выполнится:

SELECT
    username,
    created_at
FROM course_members_2022
WHERE coursename = 'PHP'

UNION

SELECT
    created_at,
    username
FROM course_members_2023
WHERE coursename = 'PHP';

С этим правилом нужно быть аккуратнее. Дело в том, что СУБД проверяет только совпадение типов данных, но не их смысл. Посмотрим, к чему это может привести. В первом подзапросе укажем столбцы coursename и username, а во втором подзапросе - наоборот:

SELECT
    coursename,
    username
FROM course_members_2022

UNION

SELECT
    username,
    coursename
FROM course_members_2023

Запрос выполнится успешно, но в результирующей таблице мы увидим вперемешку ники студентов и названия курса. Это не то, что мы хотели получить.

course_memebers

coursename username
Javascript Michaela11
PHP Kendall50
Ruby Duncan3
Kendall50 SQL
Kira94 SQL
Sylvan_Nader Python
... ...

View on DB Fiddle

Нет какого-то автоматического способа предотвратить эту ошибку, поэтому вам нужно следить за смыслом запроса самостоятельно.

Оператор UNION ALL

Перейдем к оператору UNION ALL и создадим два запроса о пользователях в 2022 году. В первом запросе изучим студентов курсов по Javascript, а во втором — курсов по Python:

SELECT username FROM course_members_2022
WHERE coursename = 'Javascript';

SELECT username FROM course_members_2022
WHERE coursename = 'Python';

Первый запрос выведет трех пользователей, а второй — двух. В целом мы получили пять записей.

js_course_memebers

username
Duncan3
Michaela11
Kendall50

python_course_memebers

username
Duncan3
Michaela11

View on DB Fiddle

А теперь объединим эти запросы с помощью UNION:

SELECT username FROM course_members_2022
WHERE coursename = 'Javascript'

UNION

SELECT username FROM course_members_2022
WHERE coursename = 'Python';

Этот запрос выведет нам только три записи.

course_memebers

username
Duncan3
Michaela11
Kendall50

View on DB Fiddle

Почему так произошло? Дело в том, что при объединении подзапросов UNION по умолчанию убирает дублирующиеся строки. Чтобы этого не происходило, добавим ALL к оператору UNION:

SELECT username FROM course_members_2022
WHERE coursename = 'Javascript'

UNION ALL

SELECT username FROM course_members_2022
WHERE coursename = 'Python';

Такой запрос вывел нам пять строк, среди которых есть два одинаковых пользователя — Michaela11 и Duncan3.

course_memebers

username
Duncan3
Michaela11
Kendall50
Michaela11
Duncan3

View on DB Fiddle

SELECT username FROM course_members_2022
WHERE coursename = 'Javascript'

UNION ALL

SELECT username FROM course_members_2022
WHERE coursename = 'Python'
ORDER BY username;

course_memebers

username
Duncan3
Duncan3
Kendall50
Michaela11
Michaela11

View on DB Fiddle

Обратим внимание, что оператор ORDER BY должен идти только в последнем подзапросе, если мы укажем его в первом, то такой запрос не сработает:

SELECT username FROM course_members_2022
WHERE coursename = 'Javascript'
ORDER BY username

UNION ALL

SELECT username FROM course_members_2022
WHERE coursename = 'Python';

Выводы

В этом уроке вы научились объединять запросы с помощью оператора UNION. Чтобы запросы срабатывали, важно соблюдать два правила: объединяемые запросы должны иметь одинаковое количество столбцов, а сами столбцы — иметь одинаковые типы данных. По умолчанию UNION удаляет дублирующиеся строки. Если повторы нужно оставить, можно использовать оператор UNION ALL.

Обратим внимание, что запрос вывел результаты в произвольном порядке, никак не упорядоченными. Чтобы упорядочить результаты, нам нужно воспользоваться оператором ORDER BY в последнем подзапросе. Если нужно упорядочить строки, то оператор ORDER BY нужно указывать в конец последнего подзапроса.


Дополнительные материалы

  1. База данных участников курсов
  2. Union

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff