РУКОВОДСТВО ПО РЕЛЯЦИОННОЙ СУБД DB2

         

КОРРЕЛИРОВАННЫЙ ПОДЗАПРОС


Выдать фамилии поставщиков, которые поставляют деталь P2. Этот пример уже рассматривался в п. 5.2.1. Однако для иллюстрации проблемы, рассматриваемой в данном разделе, приведем иное решение этой задачи.

SELECT                ФАМИЛИЯ

FROM                   S

WHERE                'P2'  IN

(SELECT НОМЕР_ДЕТАЛИ

FROM               SP

WHERE           НОМЕР_ПОСТАВЩИКА =

S. НОМЕР_ПОСТАВЩИКА);

Пояснение. В последней строке приведенного запроса неуточненная ссылка на НОМЕР-ПОСТАВЩИКА уточняется неявным образом именем таблицы SP. Другая ссылка явно уточняется именем таблицы S. Этот пример отличается от предыдущих тем, что внутренний подзапрос не может быть обработан раз навсегда прежде, чем будет обрабатываться внешний запрос, поскольку этот внутренний подзапрос зависит от переменной, а именно от S.HOMEP_ПОСТАВЩИКА, значение которой изменяется

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

а) Система проверяет первую строку таблицы S. Предположим, что это строка поставщика «S1». Тогда переменная S.НОМЕР_ПОСТАВЩИКА в данный момент имеет значение 'S1', и система обрабатывает внутренний запрос

(SELECT              НОМЕР_ДЕТАЛИ

FROM                   SP    



WHERE                НОМЕР_ПОСТАВЩИКА ='S1'),

получая в результате множество ('Р1, 'P2', 'РЗ', 'Р4', 'Р5', 'Р6'). Теперь она может завершить обработку для S1. Выборка значения ФАМИЛИЯ для S1, а именно Смит, будет произведена тогда и только тогда, когда 'Р2' принадлежит этому множеству, что, очевидно, справедливо.

б) Далее система будет повторять обработку такого рода для следующего поставщика и т. д. до тех пор, пока не будут рассмотрены все строки таблицы S.

Такой подзапрос, как в этом примере, называется коррелированным. Коррелированный подзапрос — это такой подзапрос, результат которого зависит от некоторой переменной. Эта переменная принимает свое значение в некотором внешнем запросе. Обработка такого подзапроса, следовательно, должна повторяться для каждого значения переменной в запросе, а не выполняться раз навсегда. Далее будет приведен другой пример коррелированного подзапроса (см. п. 5.2.5). Несколько других примеров приведено в разделах 5.3 и 5.4.


Для того чтобы сделать более ясной связь коррелированных подзапросов с внешними запросами, некоторые пользователи любят вводить псевдонимы (если требуется освежить в памяти вопрос относительно псевдонимов, см. пример 4.3.6 из главы 4). Например:

SELECT                SX.ФАМИЛИЯ

FROM                   S  SX

WHERE                'P2'  IN

(SELECT                     НОМЕР_ДЕТАЛИ

FROM                          SP

WHERE                       НОМЕР_ПОСТАВЩИКА=

SX.НОМЕР_ПОСТАВЩИКА);

В этом примере псевдонимом является имя SX, введенное во фразе FROM как альтернативное имя таблицы S и используемое далее в качестве явного уточнителя во фразе WHERE подзапроса, а также во фразе SELECT внешнего запроса. Действие приведенного выше полного предложения можно теперь описать более понятно и более точно следующим образом:

— SX — это переменная, областью определения которой является множество записей таблицы S, т. е. переменная, представляющая в любой заданный момент времени некоторую запись таблицы S.

— Поочередно для каждого возможного значения SX выполнить следующее:

+ вычислить подзапрос и получить множество номеров деталей, например Р;

+ добавить к результирующему множеству значение SX.ФАМИЛИЯ, если и только если P2 принадлежит множеству Р.

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

Введение псевдонима никогда не является ошибкой, а иногда оно необходимо (см. ниже пример 5.2.5).


Содержание раздела