Выбрать главу

много будет этих строк.

Коррелированный подзапрос выполняется по одному разу для каждой

строки внешнего запроса в отличие от некоррелированного подзапроса,

который выполняется единожды перед выполнением внешнего запроса.

Кроме того, коррелированный подзапрос может разрешать значения 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 используется для проверки попадания значений в список.