SQL: использование Union

В настоящее время SQL (structured query language - язык структурированных запросов) является стандартом для работы с реляционными базами данных как де-юре, в качестве стандарта ANSI, так и де-факто, поскольку его поддержку реализуют все современные серверные системы управления базами данных (DB2, Oracle, Informix, Sybase, MS SQL Server и многие другие). Реализована поддержка SQL и для настольных СУБД - Paradox, dBase, MS Access и проч. Так что роль и применимость SQL достаточно высоки. Предложения SQL просты и лаконичны, тем не менее, достижение результата исполнения таких предложений иными средствами может привести к достаточно сложному (и, безусловно, ненужному) кодированию.

О разных аспектах SQL говорить можно много, но в этой статье я хотел бы поделиться с читателями своим опытом практического использования такой его конструкции, как Union. Прошу рассматривать все изложенное с точки зрения не "как нужно делать", а "как в принципе имеется возможность делать". Надеюсь, синтаксис SQL читателю знаком.

Union позволяет объединить результаты выполнения нескольких запросов к разным таблицам в одном подмножестве данных, реализуя один запрос. Например:

select Afield1, Afield2 from A
union
select Bfield1, Bfield1 from B;

Непременное требование - одинаковые количество и типы полей в составляющих предложение Union запросах. С первым требованием (количество полей) не поспоришь. Второе (одинаковый тип) - можно обойти, для этого необходимо использовать преобразование типов в запросе. Если "родной" тип поля совпадает с типом, к которому это поле нужно привести, то преобразование не требуется. Если поля в запросе требуется как-то именовать, то это можно сделать только в первой select-секции:

 
select cast(IntegerField as char(15)) as OneField from A
union
select Char15Field from B;

Здесь IntegerField - поле типа Integer, Char15Field - поле типа char(15).

Итак, в одном подмножестве объединены числовые и строковые данные. "В огороде бузина, а в Киеве - дядька", не так ли? Для чего это нужно? Например, в области автоматизации делопроизводства возникает задача вывести список всех документов, положенных в данную папку. При этом каждый документ хранится в отдельной таблице данных. В каждой из этих таблиц есть поле FolderID, содержащее номер папки. Текст запроса к таблицам договоров и актов из папки №2 с конструированием текстовых полей в запросе и сортировкой документов по датам будет примерно такой:

select SignDate as DocumentDate,
cast(ContractKind || ' ' || ContractNumber || ' ' || ContractSubject as char(100))
from Contracts
where FolderID = 2
union
select ActDate,
cast('Акт № ' || cast(ActNumber as char(8)) || ' ' || ActName as char(100))
from Acts
where FolderID = 2;

Очевидно, что все поля, участвующие в конкатенации - типа char, а если не так, то необходимо отдельное преобразование, как это сделано с полем ActNumber, которое имеет другой тип, допустим, Integer.

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

select cast(2 as Integer) as theSequence, DocumentKind
from DocKind
union
select cast(1 as Integer) as theSequence, cast('<Все документы>' as char(40))
from OneRec
order by 1, 2;

Имеется в виду, что поле DocumentKind имеет тип char(40). Благодаря использованию фиктивного поля theSequence мы выносим запись "<Все документы>" в начало списка. (Фраза "order by 1, 2" в данном случае избыточна). Единственное "НО": необходима таблица OneRec. Что это за таблица? Это любая таблица, имеющая только одну запись - естественная или специально созданная для того, чтобы выполнить такой(ие) запрос(ы). Если записей в ней будет несколько, то будет и несколько строк "<Все документы>" в результирующем подмножестве. Можно запихать полученное подмножество в компонент DBLookupComboBox (в Delphi или C++ Builder), получится форма с одной таблицей и группировочным боксом. Естественно, реакцию программы на передвижение по такому списку придется "прописывать" вручную.

Вероятно, есть и другие примеры практического применения SQL для достижения хорошего результата простыми средствами. Буду рад, если поделитесь опытом.

Юрий А. СМАНЦЕР,
georgesman@mail.ru

Версия для печатиВерсия для печати

Номер: 

13 за 2000 год

Рубрика: 

Азбука программирования
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!
 

Комментарии

Аватар пользователя Просто студент
У меня проблема возникла во время попытки объединить поля типа автоинкремент и целое - я-то думал, это схожие типы, а оказалось - совсем нет :(

Вот такая вот история.

Аватар пользователя Патологоанатом
2 Просто студент

а через приведение типов какое-нибудь не пробовал?