Объединение результатов запроса

Иногда появляется необходимость объединить результаты запроса в одной таблице. В языке SQL это возможно осуществить с помощью оператора UNION.

Пример: необходимо отобразить всех посетителей библиотеки (и студентов и преподавателей) и книги, которые они брали

Select d1.FirstName & " " & d1.LastName As Посетитель, d2.Name As Название

From Students d1, Books d2, S_cards d3

Where

d1.Id = d3.Id_student

And

d2.Id = d3.Id_book

Union

Select d1.FirstName & " " & d1.LastName, d2.Name

From Teachers d1, Books d2, T_cards d3

Where

d1.Id = d3.Id_teacher

And

d2.Id = d3.Id_book

Order By 1;

Результат запроса представлен на рисунке

Как видите, мы получили в таблице полную информацию о посетителях.

Вообще, чтобы таблицы результатов запроса можно было объединить с помощью оператора Union, необходимо соответствие следующим требованиям:

  • Таблицы должны содержать одинаковое число столбцов
  • Тип данных каждого столбца одной таблицы должен совпадать с типом данных соответствующего столбца в другой(их) таблице(ах)
  • Ни одна из таблиц не может быть отсортирована отдельно (однако, у пользователя существует возможность отсортировать объединенный результат целиком (см. предыдущий пример))

Можно обратить внимание на то, что названия столбцов в таблицах могут не совпадать. В таком случае столбцам даются анонимные имена, которые можно переопределить (см. предыдущий пример).

Оператор Union обладает еще одним чудесным свойством - он удаляет из получившегося результата повторяющиеся строки. Если же вам чудеса не нужны, например, вы подсчитываете итоговую суммму, то от удаления повторяющихся строк можно отказаться, использовав оператор Union All (кстати, запрос, использующий Union All, вместо Union, выполняется намного быстрее).

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

Select "Студенты" As Итог, Count(*) As [Количество посетителей]

From S_cards

Union All

Select "Преподаватели", Count(*)

From T_cards

Union All

Select "Итого", Sum([Количество])

From

(

Select "Students", Count(*) As [Количество]

From S_cards

Union All

Select "Teachers", Count(*) As [Количество]

From T_cards

)

Результат выполнения запроса приведен на рисунке

В приведенном примере есть несколько необычных моментов: во-первых, выражение Count(*) возвращает количество строк в таблице (количество записей); во-вторых, запросы можно размещать внутри инструкции From. В последнем случае сначала выполняется внутренний запрос, создается временная таблица, и оператор Select уже выбирает данные из временной таблицы. Инструкция Union All здесь была необязательна, так как строки были умышленно сделаны уникальными (с помощью меток), но ее использование ускоряет выполнение запроса (не тратится время на поиск дубликатов).

Операцию Union и Union All можно использовать многократно, для объединения результатов трех и более таблиц. Предположим, что A, B, C - запросы, тогда разумно предположить, что запросы A Union B Union C, (A Union B) Union C, A Union (B Union C) выполняются с одинаковым результатом. То же самое можно сказать и запросах A Union All B Union All C, (A Union All B) Union All C, A Union All (B Union All C) - эти запросы также выполняются с одинаковым результатом.

А вот выражения (A Union All) B Union C и A Union All (B Union C) будут выполняться по-разному. В первом случае повторяющихся строк не будет, а во втором их присутствие вполне законно (последней инструкцией будет Union All). Поэтому, когда вы производите смешанное объединение рузультатов запросов, не забывайте о скобках.

Примечание: во многих СУБД не разрешается при объединении включать в инструкцию Select предложения Group By или Having; некоторые СУБД не позволяют использовать в списке возвращаемых столбцов статистические функции; более того, некоторые СУБД не поддерживают саму операцию Union (например SQL Server).