Как работает соотнесенный подзапрос

В вышеупомянутом примере, "внутренний"(inner) и "внешний"(outer), это псевдонимы, подробно обсужденным в Главе 9 . Мы выбрали эти имена для большей ясности; они отсылают к значениям внутренних и внешних запросов, соответственно. Так как значение в поле cnum внешнего запроса меняется, внутренний запрос должен выполняться отдельно для каждой строки внешнего запроса. Строка внешнего запроса, для которого внутренний запрос каждый раз будет выполнен, называется — текущей строкой-кандидатом. Следовательно, процедура оценки выполяняемой соотнесенным подзапросом — это:

Выбрать строку из таблицы, именованной в внешнем запросе. Это будет текущая строка-кандидат.
Сохранить значения из этой строки-кандидата в псевдониме с именем в предложении FROM внешнего запроса.
Выполнить подзапрос. Везде, где псевдоним данный для внешнего запроса найден ( в этом случае "внешний" ), использовать значение для текущей строки-кандидата. Использование значения из строки- кандидата внешнего запроса в подзапросе называется — внешней ссылкой.
Оценить предикат внешнего запроса на основе результатов подзапроса, выполняемого в шаге 3. Он определяет — выбирается ли строка-кандидат для вывода.
Повторить процедуру для следующей строки-кандидата таблицы, и так далее, пока все строки таблицы не будут проверены.

 
В вышеупомянутом примере, SQL осуществляет следующую процедуру:
 

Он выбирает строку Hoffman из таблицы Заказчиков. 2. Сохраняет эту строку как текущую строку-кандидат под псевдонимом — "внешним".
Затем он выполяняет подзапрос. Подзапрос просматривает всю таблицу Порядков чтобы найти строки где значение cnum поле — такое же как значение outer.cnum, которое в настоящее время равно 2001, — поле cnum строки Hoffmanа. Затем он извлекает поле odate из каждой строки таблицы Порядков для которой это верно, и формирует набор значений поля odate.
Получив набор всех значений поля odate, для поля cnum = 2001, он проверяет предикат основного запроса, чтобы видеть имеется ли значение на 3 Октября в этом наборе. Если это так(а это так), то он выбирает строку Hoffmanа для вывода ее из основного запроса.
Он повторяет всю процедуру, Используя строку Giovanni как строку-кандидата, и затем сохраняет повторно, пока каждая строка таблицы Заказчиков не будет проверена.

Как вы можете видеть, вычисления которые SQL выполяняет с помощью этих простых инструкций — это полный комплекс. Конечно, вы могли бы решить ту же самую проблему Используя объединение, следующего вида ( вывод для этого запроса показывается в Рисунке 11.2 ):
SELECT * FROM Customers first, Orders second WHERE first.cnum = second.cnum AND second.odate = 10/03/1990;

Обратите внимание что Cisneros был выбран дважды, по одному разу для каждого порядка который он имел для данной даты. Мы могли бы устранить это Используя SELECT DISTINCT вместо просто SELECT. Но это необязательно в варианте подзапроса. Оператор IN, исполяьзуемый в варианте подзапроса, не делает никакого различи между значениями которые выбираются подзапросом один раз и значениями которые выбираются неоднократно. Следовательно DISTINCT необязателен .

SQL Execution Log

SELECT *
FROM Customers first, Orders second
WHERE first.cnum = second.cnum
(SELECT COUNT (*) FROM Customers
WHERE snum = main.snum;

cnum
cname

1001
Peel

1002
Serres

Рисунок 11. 2 Использование объединения вместо соотнесенного подзапроса
Предположим, что мы хотим видеть имена и номера всех продавцов, которые имеют более одного заказчика. Следующий запрос выполнит это для вас ( вывод показывается в Рисунке 11.3 ):
SELECT snum, sname FROM Salespeople main WHERE 1 < ( SELECT COUNT (*) FROM Customers WHERE snum = main.snum );
Обратите внимание, что предложение FROM подзапроса в этом примере не использует псевдоним. При отсутствии имени таблицы или префикса псевдонима, SQL может для начала принять, что любое поле выводится из таблицы с именем, указанным в предложении FROM текущего запроса. Если поле с этим именем отсутствует( в нашем случае — snum ) в той таблице, SQL будет проверять внешние запросы. Именно поэтому, префикс имени таблицы обычно необходим в соотнесенных подзапросах — для отмены этого предполяожения. Псевдонимы также часто запрашиваются, чтобы давать вам возможность ссылаться к той же самой таблице во внутреннем и внешнем запросе без какой-либо неоднозначности.

SQL Execution Log

SELECT snum sname
FROM Salespeople main WHERE 1 <
AND second.odate = 10/03/1990;

cnum
cname
city
rating
snum

2001
Hoffman
London
100
1001

2003
Liu
San Jose
200
1002

2008
Cisneros
San Jose
300
1007

2007
Pereira
Rome
100
1004

Рисунок 11.3: Нахождение продавцов с многочисленными заказчиками
 
 
 

‹ Как сформировать соотнесенный подзапрос
Вверх
Использование соотнесенных подзапросов для нахождения ошибок ›

Айтистанция
Добавить комментарий