В некоторых случаях очень сложно вывести все необходимые данные с помощью одной команды SELECT, например, нам необходимо было бы вывести данные из одной таблицы и полученную таблицу данных дополнить строками из совершенно другой таблицы. Объединение наборов данных, получаемыми разными командами SELECT, в единую таблицу можно сделать с помощью оператора UNION или UNION ALL.
Приведу пример из нашего курса "SQL. Базы данных. ORACLE". Допустим, нужно вывести общий список сотрудников: внутренних и внештатных. Внутренние сотрудники компании ведутся в таблице PERSONS, а внештатные – в другой таблице – PERSONSEXTERNAL.
Подчеркну: мы имеем две разные таблицы, а отобразить их содержимое нужно в единой результирующей таблице. Данные одной из них вывести под данными другой, добавив, при необходимости, дополнительную информацию. Вот мы и подошли к тому, что нам нужны два SELECT-а, каждый из своей таблицы, с последующим объединением полученных данных в единую таблицу.
Итак – решаем! Выведем ФИО, Отдел, Филиал, а также столбец-признак штатный ли сотрудник или внештатный:
Две команды SELECT получают свои наборы данных, и они объединяются с помощью оператора UNION ALL в одну общую таблицу. Если нужно было бы объединить, например, три набора данных, а не два, то до фразы ORDER BY (если эта фраза, конечно, есть), можно было бы еще раз написать UNION или UNION ALL и далее добавить еще одну команду SELECT.
Мы с Вами уже привыкли, что на одну команду SELECT можно один раз писать WHERE (хоть у этого блока может быть несколько условий, объединенных AND или OR), много раз писать JOIN (да, соединений может быть сколько угодно) и один раз писать GROUP BY. ORDER BY тоже может быть только один, но если есть объединение нескольких команд SELECT, то получаемая в результате объединенная таблица может быть упорядочена только одним блоком ORDER BY. То есть на несколько UNION-ов будет только один ORDER BY. Этот блок пишется в самом конце после всех UNION-ов. В нем можно также сделать многоуровневую сортировку.
Если один или несколько UNION-ов ничего не выберут из базы данных, то, естественно, оператор UNION ничего и не добавит к общему набору данных. Если ни одна из объединенных команд ничего не вернет, то в результате получим пустой набор данных.
Первое правило, которое нужно соблюдать при объединении наборов данных, это то, что объединяемые наборы данных в общую результирующую таблицу должны иметь одинаковое количество столбцов. Как бы один SELECT продолжает довыводить данные в таблицу, которую уже построил первый SELECT. Даже если первый SELECT ничего не вернул, шапку таблицы-то он создал (заголовки столбцов)! То есть второй оператор SELECT, получая данные сначала в свой первый столбец, напишет их под данными в первый столбец предыдущего набора данных. Второй столбец поместит под вторым столбцов предыдущего набора данных и т.д.
И отсюда следует второе (и последнее) важное правило при объединении наборов данных – типы данных столбцов объединяемых наборов данных должны совпадать.
Если не понял про второе правило – поясню далее. Если понял, то можно пропустить этот абзац. Итак, например, первый селект получил текст в одном столбце, дату во втором столбце, в третьем столбце выводятся числовые данные и в последнем столбце опять текст, тогда мы должны написать второй SELECT, который продолжит выводить таблицу данных, так, чтобы первый возвращаемый столбец тоже выводил текст, второй столбец – дату, в третьем столбце было число и в четвертом – снова текст. Если в каком то из операторов SELECT нельзя вывести какой-то из столбцов, например, его просто нет в таблицах, из которых вычитывается информация вторым оператором SELECT, или он не применим ко второму набору данных, то заместо этого столбца выведем псевдостолбец с пустым значением (со значением NULL, числом 0, или, пустой строкой), как в нашем примере. В написанном выше запросе, во втором блоке SELECT нет возможности вывести столбец филиала выводящихся внештатных сотрудников, так как они не работают ни в каком филиале и в таблице PERSONSEXTERNAL столбец FilialID даже не предусмотрен. Поэтому вывели пустоту.
Вот что у нас получилось:
Названия столбцов первого набора данных могут отличаться от названий столбцов второго набора данных, присоединяемого UNION-ом. В результирующую таблицу названия столбцов всегда берутся из первого набора данных.
В чем же разница между UNION и UNION ALL. UNION ALL присоединяет все строки второго набора данных к первому, а UNION только те, которых еще в первом наборе данных нет. То есть при соединении данные с помощью UNION если строчка второго набора данных совпадает по всем перечисленным столбцам с имеющейся строкой в первом наборе данных, то она добавлена в результирующую таблицу не будет (так как она точно такая же уже есть).
Приведу пример необходимости использования UNION: банк формирует отчетность о недобросовестных клиентах. Запрос, формирующий такой список физических и юридических лиц должен выводить всю необходимую информацию о контактах клиента: ФИО, Адрес, телефон и тд. Запрос написан сложный и содержит множество подзапросов. Предположим, что через некоторое время, банк решает доработать этот отчет и в него выводить также клиентов, например, задолжающих по ипотеке. Сделанный анализ существующего запроса, на основе которого строится отчет, показал, что внесение правок в имеющуюся команду SELECT может иногда привести к ее серьёзному замедлению или дублированию данных, и поэтому принимается решение о написании еще одного SELECT, результат которого бы объединялся с имеющимся запросом. На наш вопрос аналитикам, если некоторый клиент в определенных случаях сможет быть отобран как первым SELECT-ом, так и вторым, то должен ли он отображаться в отчете два раза, мы получили единогласный ответ «нет». На основе этого ответа мы поняли, что необходимо объединять данные обоих запросов SELECT оператором UNION, а не UNION ALL.
Напишем запрос, отбирающий автомобилистов:
Получим:
К получаемым сотрудникам мы хотим добавить тех, кто работает в Москве. Добавим их отдельной командой SELECT и объединим получаемые наборы данных в одну таблицу сначала с помощью UNION ALL:
Получим:
Как видим, некоторые сотрудники отобрались как первой командой SELECT, так и были выбраны в результате второй команды SELECT. И объединены в единую результирующую таблицу. У нас есть полностью повторяющиеся строки. Видишь их? Если бы мы добавили сортировку по FIO, то сотрудники с одинаковым ФИО выводились бы рядом и тебе было бы их легче увидеть. Я подскажу тебе дубли: например, Иванов Иван Иванович или Караваева Людмила Сергеевна. Конечно разными командами SELECT можно выбрать одни и те же строки, хоть и по разным условиям, эти условия ведь не противоречащие: один и тот же сотрудник может быть как автомобилистом, так и одновременно работать в Москве.
Все строки обоих наборов данных были объединены без исключения полностью повторяющихся. Если бы мы использовали вместо UNION ALL просто UNION, то к первому набору данных присоединились бы только такие строки из второго SELECT-а, которых в первом полученном наборе данных еще нет.
Если мы воспользуемся UNION (а не UNION ALL):
То мы получим:
И напоследок еще одна важная деталь: UNION не только добавляет из второго набора данных к первому только такие строки, которых в первом нет, но и в рамках каждого объединяющегося набора данных убирает дубли. Если бы одна из команд SELECT возвращала две или более полностью одинаковые строки (то есть такие, значения в которых по всем столбцам повторяются со значениями другой строки), то даже в рамках одного объединяющегося набора данных, из всех дублей осталась бы одна строка. То есть UNION делает DISTINCT, а UNION ALL - нет.
Буду рад, если подпишешься на мой канал или оставишь комментарий к моему посту!
Заходи на наш Youtube-канал и найдёшь много интересного и полезного про базы данных и язык SQL. Кстати, в одном из роликов на нашем YouTube-канале, я разбирал вопросы с собеседования по SQL. Одним из вопросов был: "В чем разница между UNION и UNION ALL". Вот ссылка на это видео: https://youtu.be/dNNBKriXYdI.
Если у тебя есть Telegram, подписывайся на наш канал. Несколько раз в неделю решаем вместе разные задачи по SQL, и еще помогаю не выпадать из темы айти. Делюсь полезной информацией и техническим-юмором:)
А здесь ты можешь пройти наш курс обучения языку SQL и получить мощные знания и умения! Всего за 27 уроков до уровня специалиста, имеющего трёхлетний стаж. Много практики в реальной базе данных! С нашей поддержкой и проверкой твоих самостоятельный задач! Записывайся, буду тебя ждать!