Sql Scholl
Распечатать страницу
Перейти на главную Карта сайта Отправить сообщение

Подзапросы

Фильтрация посредством подзапросов

      Таблицы баз данных, используемые во всех уроках этой книги, являются реляционными таблицами. Заказы хранятся в двух таблицах. Таблица Orders (заказы) содержит по одной строке для каждого заказа; в ней указываются номер заказа, идентификатор клиента и дата заказа. Предметы отдельного заказа хранятся в соответствующей таблице Orderltems. Таблица Orders не содержит информацию о клиентах. Она хранит только идентификатор клиента. Информация о клиентах хранится в таблице Customers (клиенты).

       Теперь предположим, что вы хотите получить перечень всех клиентов, которые заказали продукт RGAN01. Что нужно сделать, чтобы получить эту информацию? Для этого нужно сделать следующее.

       1.    Выбрать номера всех заказов, в которых содержится продукт RGAN01.

       2.    Выбрать идентификатор клиента для всех клиентов, которые имеют заказы, перечисленные среди номеров заказов, возвращенных на предыдущем шаге.

       3.    Выбрать информацию о клиенте для всех клиентов, идентификаторы которых были возвращены на предыдущем шаге.

       Каждый из этих шагов можно выполнить в виде отдельного запроса. Делая это, вы используете результаты, возвращенные одним оператором SELECT, чтобы заполнить предложение WHERE для следующего оператора SELECT.

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

     Первый оператор SELECT выбирает столбец order_num для всех продуктов заказа, у которых в столбце prod_id значится RGAN01. Результат представляет собой номера двух заказов, содержащих этот предмет:

SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGANOl' 



order_num 
---------------------------
20007 
20008

      Следующий шаг состоит в выборке идентификаторов клиентов, связанных с заказами 20007 и 20008. Используя предложение IN, о котором говорилось в разеле, "Расширенная фильтрация данных", вы можете создать такой оператор SELECT:

SELECT cust_id
FROM Orders
WHERE order num IN (20007,20008); 




cust_id 
----------------------
1000000004 
1000000005

      Теперь объединим эти два запроса путем превращения первого из них (того, который возвращает номера заказов) в подзапрос. Посмотрите на следующий оператор SELECT:

SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
FROM Orderltems
WHERE prod_id = 'RGANOl); 



cust_id 
---------------------
10000004 
10000005

     Подзапросы всегда обрабатываются, начиная с самого внутреннего оператора SELECT в направлении "изнутри наружу". При обработке предыдущего оператора СУБД в действительности выполняет две операции.

     Вначале она выполняет подзапрос:
     SELECT order_num FROM orderitems WHERE prod_id='RGANO1'
     В результате выполнения этого запроса возвращается два номера заказа, 20007 и 20008. Эти два значения затем передаются в предложение WHERE внешнего запроса в формате с разделителем в виде запятой, необходимом для оператора IN. Теперь внешний запрос становится таким: SELECT cust_id FROM orders WHERE order_num IN (20007,20008)

     Как видите, результат корректен и точно такой же, как полученный путем жесткого кодирования предложения WHERE в предыдущем примере.

Форматируйте ваши Подзапросы

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

      Теперь у нас есть идентификаторы всех клиентов, заказавших продукт RGANOl. Следующий шаг состоит в получении клиентской информации для каждого из этих идентификаторов клиентов. Оператор SQL, осуществляющий выборку двух столбцов, таков:

SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN ('1000000004','1000000005');

     Вместо жесткого указания идентификаторов клиентов вы можете превратить данное предложение WHERE в подзапрос:

SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (SELECT cust_id FROM Orders WHERE order_num IN (SELECT order_num FROM OrderItems WHERE prod_id = 'RGANOl')); 



cust_name         cust_contact 
--------------    -----------------------
Fun4All           Denise L. Stephens
The Tov Store     Kim Howard

      Чтобы выполнить вышеприведенное выражение SELECT, СУБД должна в действительности выполнить три оператора SELECT. Самый внутренний подзапрос возвращает перечень номеров заказов, который затем используется как предложение WHERE для подзапроса, внешнего по отношению к данному. Этот подзапрос возвращает перечень идентификаторов клиентов, которые используются в предложении WHERE запроса более высокого уровня. Запрос верхнего уровня возвращает искомые данные.

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

Только один столбец

Операторы select подзапроса могут выбирать только один столбец. Попытка произвести выборку нескольких столбцов приведет к появлению сообщения об ошибке.

Подзапросы и производительность

Представленные нами коды работают и приводят к получению необходимых результатов. Однако подзапросы — не всегда наиболее эффективный способ выборки данных такого типа. Более подробно об этом рассказано в разделе, "Объединение таблиц", в котором повторно будет рассмотрен этот же самый пример.