Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Базы данных / БД2012 / Understanding.SQL.doc
Скачиваний:
283
Добавлен:
28.03.2015
Размер:
1.75 Mб
Скачать

Использование подзапросов с insert

INSERT - это самый простой случай. Вы уже видели как вставлять результаты запроса в таблицу. Вы можете использовать подзапросы внутри любого запроса, который генерирует значения для команды INSERT тем же самым способом, которым вы делали это для других запросов - т.е. внутри предиката или предложения HAVING. Предположим, что мы имеем таблицу с именем SJpeople, столбцы которой совпадают со столбцами нашей таблицы Продавцов. Вы уже видели как заполнять таблицу подобно этой, заказчиками в городе, например, в San Jose:

INSERT INTO SJpeople

SELECT *

FROM Salespeople

WHERE city = 'San Jose';

Теперь мы можем использовать подзапрос чтобы добавить к таблице 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 этого нового подзапроса, а, как мы говорили ранее, вы не можете ссылаться на таблицу которая задействована ( целиком ) в любом подзапросе команды модификации. В случае INSERT, это будет также препятствовать соотнесенным подзапросам, основанным на таблице в которую вы вставляете значения. Это имеет значение, потому что, с помощью INSERT, вы создаете новую строку в таблице. "Текущая строка" не будет существовать до тех пор, пока INSERT не закончит ее обрабатывать.

Использование подзапросов созданных во внешней таблице запроса

Запрещение на ссылку к таблице которая модифицируется командой INSERT не предохранит вас от использования подзапросов которые ссылаются к таб- лице используемой в предложении FROM внешней команды SELECT. Таблица из которой вы выбираете значения, чтобы произвести их для INSERT , не будет задействована командой; и вы сможете ссылаться к этой таблице любым способом, которыми вы обычно это делали, но только если эта таблица указана в автономном запросе. Предположим что мы имеем таблицу с именем Samecity в ко- торой мы запомним продавцов с заказчиками в их городах. Мы можем заполнить таблицу используя соотнесенный подзапрос:

INSERT INTO (Samecity

SELECT *

FROM (Salespeople outer

WHERE city IN

( SELECT city

FROM Customers inner

WHERE inner.snum = outer.snum );

Ни таблица Samecity, ни таблица Продавцов не должны быть использованы во внешних или внутренних запросах INSERT. В качестве другого примера, предположим, что вы имеете премию для продавца который имеет самый большой порядок на каждый день. Вы следите за ним в таблице с именем Bonus, которая содержит поле snum продавцов, поле odate и поле amt . Вы должны заполнить эту таблицу информацией которая хранится в таблице Порядков, используя следующую команду:

INSERT INTO Bonus

SELECT snum, odate, amt

FROM Orders a

WHERE amt =

( SELECT MAX (amt)

FROM Orders b

WHERE a.odate = b.odate );

Даже если эта команда имеет подзапрос который базируется на той же самой таблице что и внешний запрос, он не ссылается к таблице Bonus, на которую воздействует команда. Что для нас абсолютно приемлемо. Логика запроса, естественно, должна просматривать таблицу Порядков, и находить для каждой строки максимум порядка сумм приобретений для этой даты. Если эта величина - так же как у текущей строки, текущая строка является наибольшим порядком для этой даты, и данные вставляются в таблицу Bonus.

Соседние файлы в папке БД2012