много будет этих строк.
Коррелированный подзапрос выполняется по одному разу для каждой
строки внешнего запроса в отличие от некоррелированного подзапроса,
который выполняется единожды перед выполнением внешнего запроса.
Кроме того, коррелированный подзапрос может разрешать значения NULL.
В последующих разделах вы увидите примеры, которые иллюстрируют
эти идеи.
Пример коррелированного подзапроса
Следующий коррелированный подзапрос отбирает товары, цена которых
выше средней цены товаров этой группы:
П SELECT product_id, product_type_id, паше, price
FROM products outer
WHERE price >
(SELECT AVG(price)
FROM products inner
WHERE inner.product_type_id = outer.product_type_id);
ID PRODUCT_TYPE_ID NAME PRICE
2 1 Chemistry 30
5 2 Z F ile s 45.99
7 3 Space Force 9 13.49
10 4 Pop 3 15.99 11
4 C re a tiv e Y e ll 14.99
Подзапросы 183
Чтобы пометить внешний запрос, используется псевдоним outer, а для
внутреннего запроса - inner. Ссылка на столбец produ ct_type_id во внутренней
и внешней частях - этот как раз то, что делает внутренний подзапрос
коррелированным с внешним запросом. Кроме того, подзапрос возвращает
одну строку, содержащую среднюю цену товара.
В коррелированном подзапросе строки внешнего запроса по очереди
передаются в подзапрос. В свою очередь подзапрос построчно читает из
внешнего запроса и применяет прочитанную строку к подзапросу, пока не
будут обработаны все строки внешнего запроса. После этого возвращаются
результаты всего запроса в целом.
В предыдущем примере внешний запрос выбирает каждую строку из
таблицы products и передает ее во внутренний запрос. Каждая строка прочитывается
внутренним запросом, тот вычисляет среднее значение цены
для каждого товара, для которого значение produ ct_type_ id во внутреннем
запросе равно значению p rodu ct_type_id во внешнем запросе.
Использование операторов EXISTS и NOT EXISTS с коррелированными
подзапросами
Оператор EXISTS используется для проверки, существует ли хоть одна строка,
возвращенная подзапросом. Хотя оператор EXISTS можно использовать
не только для коррелированных подзапросов, обычно он используется
именно в них. Оператор NOT EXISTS является логическим отрицанием оператора
EXISTS. Он используется в тех случаях, когда необходимо проверить,
что не существует ни одной строки, возвращенной подзапросом.
Использование оператора EXISTS в коррелированных
подзапросах
В следующем примере оператор EXISTS используется для отбора служащих,
которые управляют другими служащими. Обратите внимание, что не важно,
сколько строк возвращает подзапрос; мне важно знать, возвращаются
ли в принципе какие-либо строки:
□ SELECT employee_id, last_name
FROM employees outer
WHERE EXISTS
(SELECT employee_id
FROM employees inner
WHERE inner.manager_id = outer.employee_id);
EMPLOYEE_ID LAST_NAME
1 Smith
2 Johnson
Поскольку оператор EXISTS лишь проверяет сам факт существования
строк, возвращаемых подзапросом, подзапрос не обязан возвращать столбец:
можно возвратить литеральное значение, что может повысить производительность
запроса. В следующем примере показан переписанный запрос
из предыдущего примера, в котором подзапрос возвращает литеральное
значение 1:
184 Глава 6
□ SELECT employee_id, last_name
FROM employees outer
WHERE EXISTS
(SELECT 1
FROM employees inner
WHERE inner.managerJLd = outer.employee_id);
EMPLOYEE_ID LAST.NAME
1 Smith
2 Johnson
До тех пор, пока подзапрос возвращает одну или более строк, EXISTS
возвражает true; если подзапрос не возвращает строк, EXISTS возвращает
false. В примерах я не обращал внимания на то, как много строк возвращает
подзапрос: я только обращал внимание, возвращаются (или не возвращаются)
какие-либо строки в принципе, так что EXISTS даёт true (или false).
Поскольку внешний запрос требует как минимум один столбец, подзапрос
в предыдущем примере возвращает литеральное значение 1.
Использование N O T EXISTS с коррелированными
подзапросами
В следующем примере оператор NOT EXISTS используется для отбора товаров,
которые ни разу не были проданы:
□ SELECT product_id, name
FROM products outer
WHERE NOT EXISTS
(SELECT 1
FROM purchases inner
WHERE inner.product_id = outer.product_id);
_Ю NAME
4 Tank War
5 Z F ile s
6 2412: The Return
7 Space Force 9
8 From Another P lan et
9 C la s s ic a l Music
10 Pop 3
11 C re a tiv e Y e ll
12 My Front Line
EXISTS и N O T EXISTS против IN и N O T IN
В разделе «Использование IN с многострочными подзапросами» показано,
как оператор IN используется для проверки попадания значений в список.