16
ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ
С КОМАНДАМИ МОДИФИКАЦИИ
196 ПОНИМАНИЕ SQL ___________________________________________________________________
ГЛ. 16
В ЭТОЙ ГЛАВЕ, ВЫ УЗНАЕТЕ КАК ИСПОЛЬЗОВАТЬ
подзапросы в командах модификации.
Вы найдете, что нечто подобное - вы уже видели при использовании под-
запросов в запросах. Понимание, как подзапросы используются в коман-
дах SELECT, cделает их применение в командах модификации более уве-
ренным, хотя и останутся некоторые вопросы.
Завершением команды SELECT является подзапрос, но не предикат, и по-
этому его использование отличается от использования простых предика-
тов с командами модификации, которые вы уже выполняли ранеее с ко-
мандами UPDATE и DELETE. Вы использовали простые запросы чтобы
производить значения для INSERT, а теперь мы можем расширить эти
запросы чтобы включять в них подзапросы.
Важный принцип который надо соблюдать при работе с командами
модификации, состоит в том, что вы не можете в предложении FROM
любого подзапроса, модифицировать таблицу к которой ссылаетесь с
помощью основной команды. Это относится ко всем трем командам мо-
дификации. Хотя имеется большое количество ситуаций в которых будет
полезно сделать запрос той таблицы которую вы хотите модифицировать
причем во время ее модификации, это слишком усложняет операцию что-
бы использовать ее на практике.
Не делайте ссылки к текущей строке таблицы указанной в команде,
которая является соотнесенным подзапросом.
==== ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С INSERT ===
INSERT - это самый простой случай. Вы уже видели как вставлять
результаты запроса в таблицу. Вы можете использовать подзапросы
внутри любого запроса, который генерирует значения для команды
INSERT тем же самым способом, которым вы делали это для других
запросов - т.е. внутри предиката или предложения HAVING.
Предположим, что мы имеем таблицу с именем SJpeople, столбцы
которой совпадают со столбцами нашей таблицы Продавцов.
Вы уже видели как заполнять таблицу подобно этой, заказчиками в
городе, например, в San Jose:
Insert into sJpeople
SELECT *
FROM Salespeople
WHERE city = 'San Jose';
ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С КОМАНДАМИ МОДИФИКАЦИИ 197
______________________________________________________________________
Теперь мы можем использовать подзапрос чтобы добавить к таблице
SJpeople всех продавцов которые имеют заказчиков в San Jose, неза-
висимо от того, находятся ли там продавцы или нет:
Insert into sJpeople
SELECT *
FROM Salespeople
WHERE snum = ANY
( SELECT snum
FROM Customers
WHERE city = ' (San (Jose' );
Оба запроса в этой команде функционируют также как если бы они не
являлись частью выражения INSERT. Подзапрос находит все строки для
заказчиков в San Jose и формирует набор значений snum. Внешний запрос
выбирает строки из таблицы Salespeople, где эти значения snum найдены.
В этом примере, строки для продавцов Rifkin и Serres, которые назначены
заказчикам в San Jose - Liu и Cisneros, будут вставлены в таблицу SJpeople.
НЕ ВСТАВЛЯЙТЕ ДУБЛИКАТЫ СТРОК
Последовательность команд в предшествующем разделе может быть
проблематичной. Продавец Serres находится в San Jose, и следовательно
будет вставлен с помощью первой команды. Вторая команда попытается
вставить его снова, поскольку он имеет еще одного заказчика в San Jose.
Если имеются любые ограничения в таблице SJpeople которые вынужда-
ют ее значения быть уникальными, эта вторая вставка потерпит неудачу
( как это и должно было быть).
Двойные строки это плохо. ( См. Главу 18 для подробностей об ограниче-
ниях. )
Было бы лучше если бы вы могли как-то выяснить, что эти значения уже
были вставлены в таблицу, прежде чем вы попытаетесь сделать это снова,
с помощью добавления другого подзапроса ( использующего операторы
типа EXISTS, IN, < > ALL, и так далее ) к предикату.
К сожалению, чтобы сделать эту работу, вы должны будете сослаться на
саму таблицу SJpeople в предложении FROM этого нового подзапроса, а,
как мы говорили ранее, вы не можете ссылаться на таблицу которая
198 ПОНИМАНИЕ SQL
______________________________________________________________________
ГЛ. 16
задействована ( целиком ) в любом подзапросе команды модификации.
В случае INSERT, это будет также препятствовать соотнесенным подзапро-
сам, основанным на таблице в которую вы вставляете значения. Это имеет
значение, потому что, с помощью INSERT, вы создаете новую строку в таб-
лице. "Текущая строка" не будет существовать до тех пор, пока INSERT не
закончит ее обрабатывать.
ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ СОЗДАНЫХ
ВО ВНЕШНЕЙ ТАБЛИЦЕ ЗАПРОСА
Запрещение на ссылку к таблице которая модифицируется командой INSERT
не предохранит вас от использования подзапросов которые ссылаются к таб-
лице используемой в предложении FROM внешней команды SELECT. Таблица
из которой вы выбираете значения, чтобы произвести их для INSERT , не будет
задействована командой; и вы сможете ссылаться к этой таблице любым спосо-
бом которыми вы обычно это делали, но только если эта таблица указана в авто-
номном запросе. Предположим что мы имеем таблицу с именем Samecity в ко-
торой мы запомним продавцов с заказчиками в их городах.
Мы можем заполнить таблицу используя соотнесенный подзапрос: