Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Гайдамакин Н. А. Автоматизированные информационные системы, базы и банки данных. Вводный курс.doc
Скачиваний:
372
Добавлен:
02.05.2014
Размер:
4.3 Mб
Скачать

4.3.2.4. Подчиненные (сложные) запросы

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

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

Второй вариантреализуется черезвключениев тело внеш­ней (главной)SQL-инструкции внутренней инструкции SELECT.При этом результат исполнения внутренней инструк­цииSELECTиспользуется для формирования условия отбора записей в главном (внешнем) запросе или в качестве выраже­ния для нового вычисляемого поля. Такие запросы называютсяподчиненными.

Использование внутренней инструкции SELECT для фор­мирования условий отбора записей во внешнем запросевозмож­но одним изтрехспособов:

• через предикаты сравнения «для некоторых/для всех» — ANY, SOME, ALL;

• через предикат вхождения IN;

• через предикат существования EXISTS.

В первом способеконструкция запроса может выглядеть следующим образом:

SELECT.. FROM...WHEREВыражение[ANY|SOME|ALL](SELECT...);

где — оператор сравнения.

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

Предикаты ANYи SOME («для некоторых»),являющие­ся синонимами, используются для отбора в главной SQL-инст-рукции тех записей, которые удовлетворяют сравнениюс ка­кой-либо записью(т. е.хотя бы с одной),из отобранных во внут­ренней инструкции SELECT.

Для примера на рис. 4.23, априведен запрос по отбору из таблицы «Заявки» тех записей, которые могут быть удовлетво­рены в соответствии с данными по таблице «Квартиры», т. е. тех записей из таблицы «Заявки», которые удовлетворяют срав­нению по полям «КолКомп», «Площадь» и «Этаж» хотя бы с некоторыми (ANY)записями из таблицы «Квартиры», выбира­емыми при условии «Продано=Нет».

Рис. 4.23, а. Пример подчиненного запроса на основе предиката ANY

Предикат ALL (для всех)используется для отбора в глав­ном запросе только тех записей, которые удовлетворяют сравнениюодновременно со всеми записями,отобранными в под­чиненном запросе. Пример выполнения запроса с предикатомALLприведен на рис. 4.23,б.

Рис. 4.23, б. Пример подчиненного запроса па основе предиката ALL

Принцип действия запроса по второму способузаключа­ется в поиске среди результирующего набора записей внешней SQL-инструкции тех записей, для которых значение определен­ного выражения входит в список записей, отбираемых внутренней инструкцией SELECT.Конструкция запроса с предика­том INвыглядит следующим образом:

SELECT ... FROM ... WHEREВыражение [NOT]IN (SELECT...);

В качестве примера на рис. 4.24 приведен запрос по тем же исходным данным (таблицы «Сотрудники» и «Премирование») для отбора записей только тех сотрудников, записи которых по премиям были в списке премий, равных или превышающих 100%.

Рис. 4.24. Пример с подчиненным запросом на основе предиката IN

Следует добавить, что предикат NOT INиспользуется для отбора во внешней SQL-инструкции только тех записей, кото­рые содержат значения, не совпадающие ни с одним из ото­бранных внутренней инструкцией SELECT.

В третьем способепостроения подчиненного запроса пре­дикат EXISTS(с необязательным зарезервированным словомNOT)используется в логическом выражении для определения того, должен ли подчиненный запросвозвращать какие-либо записи.Исходя из этого, каждая запись, отбираемая во внеш­ней SQL-инструкции, идет в итоговый набор данных только тог­да, когда при ее условиях отбирается (существует) хотя бы одна запись по внутренней инструкции SELECT.Конструкция зап­роса в этом случае может выглядеть следующим образом:

SELECT...FROM..WHERE([NOT]Exists(SELECT...));

В следующем примере на рис. 4.25 по таблицам, представ­ленным на рис. 4.24, иллюстрируется запрос по отбору запи­сей сотрудников, премированных хотя бы один раз, т.е. таких, у которых существует запись в списке премированных.

Рис. 4.25. Пример с подчиненным запросом на основе предиката EXISTS

Следует заметить, что использование предиката NOT EXISTSсформирует список ни разу не премированных сотруд­ников. В последнем примере можно также увидеть, что альтер­нативным решением для реализации такого запроса является использование запроса на внутреннее соединение (INNER JOIN).

Внутренняя инструкция SELECT может также использо­ваться в качестве выражения для вычисляемого поля внешней SQL-инструкции. Конструкция запроса в этом случае может выглядеть следующим образом:

SELECT...(SELECT...ИмяВычПоляFROM..WHERE...;

Обязательным условием при этом является то, чтобы внут­ренняя инструкция SELECT для каждой отбираемой по внеш­ней SQL-инструкции записи возвращала не более чем одну за­пись но не более чем одному полю.

Приведем пример подобного запроса, отбирающего все за­писи по полю «Марка» из таблицы «Товары», с формированием дополнительного поля «Категория», значения которого воз­вращаются внутренней инструкцией LЕСТ из таблицы «ТипыТоваров» при условии совпадения значения поля «КодТипа» из таблицы «Товары» для текущей записи внешней SQL-инструкции с аналогичным полем «КодТипа» в записях таблицы «ТипыТоваров»:

SELECTТовары.Марка, (SELECTТипыТоваров.КатегорияFRОМТипы

WHERE(Товары.КодТипа=ТипыТоваров.КодТипа);)

ASКатегория

FROMТовары;

Нетрудно заметить, что целью использования в данном при­мере внутренней инструкции SELECT является формирование в наборе данных, отбираемых из таблицы на стороне «Мно­гие», дополнительного поля по значению какого-либо поля из связанной таблицы на стороне «Один». Исходя из этого, аль­тернативным способом решения данной задачи может быть ис­пользование запроса на внутреннее соединение:

SELECTТовары.Марка,ТипыТоваров.Категория

FROMТовары INNERJOINTТипыТоваровONТовары.Код-Типа = ТипыТоваров.КодТипа;

В тех случаях, когда отбор данных внешней SQL-инструкцией осуществляется из таблицы на стороне «Один», внутрен­няя инструкция SELECT может использоваться для дополни­тельного поля, формируемого на основе групповой операции по группам соответствующих связанных записей в таблице на стороне «Многие». Приведем пример отбора записей по полю «Категория» из таблицы «ТипыТоваров» с дополнительным полем «СредняяЦена», формируемым на основе статистичес­кой функции AVGпо полю «Цена» для групп связанных запи­сей в таблице «Товары»:

SELECTТипыТоваров.Категория, (SELECT Avg(Toвары.Цена)

ASСредняяЦена

FROMТовары

GROUPВYТовары.КодТипа

НАVING(ТипыТоваров.КодТипа=Товары.КодТипа);)АSСред­няяЦена

FROMТипыТоваров;

Опять-таки отметим, что альтернативным решением по данному примеру может быть использование следующего зап­роса на внутреннее соединение:

SELECTТипыТоваров.Категория, Avg(Toвapы.Цена) AS СредняяЦена

FROMТипыТоваров INNER JOINTТовары ON ТипыТоваров.КодТипа=Товары.КодТипа

GROUP ВY ТипыТоваров.Категория;