Объединение UNION

Для объединения результатов двух и более SQL-запросов в единую таблицу применяется ключевое слово UNION. Запросы должны возвращать одинаковое число и последовательность совместимых типов данных в соответствующих столбцах.

Синтаксис применения SQL запроса UNION

Оператор UNION размещается между SQL запросами :

select user_id, userName, phone from users
UNION [ALL]
select city_id, cityName, region from cities
UNION [ALL]
select company_id, companyName, address from companies

В представленном примере в одну кучу свалили информацию из трех таблиц, имеющих однотипные столбцы, что, конечно, неправильно, но это работает.

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

UNION может быть использован совместно с оператором ALL для получения всех записей. Но необходимо отметить, что UNION ALL работает быстрее, чем просто UNION, поскольку при использовании оператора UNION проводится дополнительная фильтрация результата аналогичная SELECT DISTINCT, а при использовании UNION ALL — нет.

Правила применения UNION

При использовании UNION необходимо соблюдать несколько правил, регламентирующих порядок применения оператора :

  • совместимость типов данных в соответствующих столбцах запросов;
  • одинаковое число столбцов во всех объединяемых запросах;
  • запрет пустых значений (NULL) в любом столбце объединения;
  • нельзя использовать UNION в подзапросах.

Тип столбцов нескольких запросов может не совпадать, но обязательно должен быть совместимым путем неявного преобразования. Следует помнить, что столбцы с типом данных XML должны быть эквивалентными, т.е. тип столбцов должен быть определен либо в XML-схеме, либо быть нетипизированными. Типизированные столбцы должны относиться к одной и той же коллекции XML-схем.

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

В качестве примера рассмотрим две простенькие таблицы (архивная и рабочая) без определения первичных и внешних ключей, индексов, ограничений на значения колонок и прочих "прелестей" SQL-языка. Допускаем, что в архивной таблице хранится информация о заказах за прошедшие годы. В рабочей таблице размещаются текущие продажи/заказы. Список товаров и услуг, входящих в заказ, не рассматриваем.

Архивная таблица заказов :

create table archive (
  id     int          not null,   -- идентификатор записи
  mid    int          not null,   -- идентификатор менеджера
  year   int          not null,   -- год
  month  int          not null,   -- месяц
  total  decimal(9,4) not null  
);

insert into archive (id, mid, year, month, total) values (1, 2, 2013, 1, 23500);
insert into archive (id, mid, year, month, total) values (2, 2, 2013, 2, 11534);
insert into archive (id, mid, year, month, total) values (3, 2, 2013, 3, 17532);
insert into archive (id, mid, year, month, total) values (4, 2, 2013, 4, 23543);
insert into archive (id, mid, year, month, total) values (5, 2, 2013, 5, 23245);

Рабочая таблица заказов :

create table orders (
  id     int          not null,  -- идентификатор заказа
  mid    int          not null,  -- идентификатор менеджера
  total  decimal(9,4) not null,
  data   datetime     not null  
);

insert into orders (id, mid, total, data) values (1, 1, 1350, '2014-02-23');
insert into orders (id, mid, total, data) values (2, 2, 3250, '2014-02-24');

Использование UNION ALL

Запрос выборки данных по продажам товаров (предоставлении услуг) по месяцам за весь период :

select CONCAT(CONVERT(year, CHAR (4)), '.', CAST(month as CHAR(2))) AS data, total
  from archive
  
UNION ALL

select CONVERT(DATE_FORMAT(data, '%Y.%m'), CHAR (7)), SUM(total)
  from orders
     GROUP BY DATE_FORMAT(data, '%Y.%m')

order by 1;

Не следует относиться критично к конкатенации и функции преобразования даты; для различных СУБД это может различаться.

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

data     total
--------------------
2013.1 	 23500.0000
2013.2	 11534.0000
2013.3   17532.0000
2013.4	 23543.0000
2013.5	 23245.0000
2014.2	  4600.0000

Использование UNION

Запрос выборки данных по продажам товаров (предоставлении услуг) по месяцам за весь период для определенного менеджера :

select CONCAT(CONVERT(year, CHAR (4)), '.', CAST(month as CHAR(2))) AS data, total
  from archive
    where mid = 2
UNION ALL

select CONVERT(DATE_FORMAT(data, '%Y.%m'), CHAR (7)), SUM(total)
  from orders
     where mid = 2
     GROUP BY DATE_FORMAT(data, '%Y.%m')

order by 2;

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

data     total
--------------------
2014.2	 3250.0000
2013.2	11534.0000
2013.3	17532.0000
2013.5	23245.0000
2013.1	23500.0000
2013.4	23543.0000

Записи в результирующем наборе можно упорядочить с помощью одного или нескольких полей с использованием оператором ASC или DESC. Номер 1 и 2 в предложении ORDER BY указывает по какому столбцу результирующего набора будет упорядочен результат выборки.

Так как столбцы объединения - это столбцы вывода, они не имеют имен, и следовательно, должны определяться по номеру. Этот номер указывает на их место среди других столбцов вывода.

Внешнее объединение с UNION

При помощи UNION можно создавать полные внешние объединения :

SELECT e.id as eid, d.id as did, e.name as employee, d.name as department
   FROM employee e
   LEFT JOIN department d
      ON e.did = d.id
UNION
SELECT e.id as eid, d.id as did, e.name as employee, d.name as department
   FROM employee e
   RIGHT JOIN department d
     ON e.did = d.id;

Иногда в запросы вставляют дополнительное отладочное поле, чтобы понять к какому SELECT относится текущая запись набора.

SELECT e.id as eid, d.id as did, e.name as employee, d.name as department, 'first'
   FROM employee e
   LEFT JOIN department d
      ON e.did = d.id
UNION
SELECT e.id as eid, d.id as did, e.name as employee, d.name as department, 'second'
   FROM employee e
   RIGHT JOIN department d
     ON e.did = d.id;
  Рейтинг@Mail.ru