Мартин Грубер - Понимание SQL (991940), страница 25
Текст из файла (страница 25)
Например, чтобы изменить оценки всех заказчиков на 200, вы можете ввестиUPDATE CustomersSET rating = 200;МОДИФИЦИРОВАНИЕ ТОЛЬКО ОПРЕДЕЛЕННЫХ СТРОККонечно, вы не всегда захотите указывать все строки таблицы для измененияединственного значения, так что UPDATE, наподобии DELETE, может брать предикаты. Вот как например можно выполнить изменение одинаковое для всех заказчиковпродавца Peel (имеющего snum=1001):UPDATE CustomersSET rating = 200WHERE snum = 1001;КОМАНДА UPDATE ДЛЯ МНОГИХ СТОЛБЦОВОднако, вы не должны ограничивать себя модифицированием единственногостолбца с помощью команды UPDATE.
Предложение SET может назначать любоечисло столбцов, отделяемых запятыми. Все указанные назначения могут быть сделаны для любой табличной строки, но только для одной в каждый момент времени.Предположим, что продавец Motika ушел на пенсию, и мы хотим переназначить егономер новому продавцу:UPDATE SalespeopleSET sname = 'Gibson', city = 'Boston', comm = .10WHERE snum = 1004;Эта команда передаст новому продавцу Gibson, всех текущих заказчиков бывшего продавца Motika и порядки, в том виде в котором они были скомпонованы дляMotika с помощью поля snum.Вы не можете, однако, модифицировать сразу много таблиц в одной команде,частично потому, что вы не можете использовать префиксы таблицы со столбцамиизмененными предложением SET. Другими словами, вы не можете сказать — "SETSalespeople.sname = Gibson" в команде UPDATE, вы можете сказать только так —"SET sname = Gibson".ИСПОЛЬЗОВАНИЕ ВЫРАЖЕНИЙ ДЛЯ МОДИФИКАЦИИВы можете использовать скалярные выражения в предложении SET командыUPDATE, однако, включив его в выражение поля которое будет изменено.
В этом ихотличие от предложения VALUES команды INSERT, в котором выражения не могутиспользоваться; это свойство скалярных выражений — весьма полезная особенность.Предположим, что вы решили удвоить комиссионные всем вашим продавцам. Вы можете использовать следующее выражение:UPDATE SalespeopleSET comm = comm * 2;Всякий раз, когда вы ссылаетесь к указанному значению столбца в предложенииSET, произведенное значение может получится из текущей строки, прежде в ней будут сделаны какие-то изменения с помощью команды UPDATE.
Естественно, вы можете скомбинировать эти особенности, и сказать, — удвоить комиссию всемпродавцам в Лондоне, таким предложением:UPDATE SalespeopleSET comm = comm * 2WHERE city = 'London';МОДИФИЦИРОВАНИЕ ПУСТЫХ(NULL) ЗНАЧЕНИЙПредложение SET — это не предикат. Он может вводить пустые NULL значениятакже, как он вводил значения, не используя какого-то специального синтаксиса (такого, например, как IS NULL).
Так что, если вы хотите установить все оценки заказчиковв Лондоне в NULL, вы можете ввести следующее предложение:UPDATE customersSET rating = NULLWHERE city = 'London';что обнулит все оценки заказчиков в Лондоне.РЕЗЮМЕТеперь вы овладели мастерством управления содержанием вашей базы данныхс помощью трех простых команд:INSERT— используемой чтобы помещать строки в базу данных;DELETE— чтобы удалять их;REFERENCES — чтобы изменять значения в уже вставленных строках.Вы обучались использованию предиката с командами UPDATE и DELETE чтобыопределять, на которую из строк будет воздействовать команда.
Конечно, предикатыкак таковые — не значимы для INSERT, потому что обсуждаемая строка не существует в таблице до окончания выполнения команды INSERT. Однако, вы можете использовать запросы с INSERT, чтобы сразу помещать все наборы строк в таблицу. Причемэто, вы можете делать со столбцами в любом порядке.Вы узнали, что значения по умолчанию, могут помещаться в столбцы, если вы неустанавливаете это значение явно. Вы также видели использование стандартногозначения по умолчанию, которым является NULL. Кроме того, вы поняли, что UPDATEможет использовать выражение значения, тогда как INSERT не может.Следующая глава расширит ваше познания, показав вам, как использовать подзапросы с этими командами.
Эти подзапросы напоминают те, с которыми вы уже знакомы, но имеются некоторые специальные выводы и ограничения, когда подзапросыиспользуются в командах DML, что мы будем обсуждать в Главе 16.РАБОТА С SQL1. Напишите команду, которая бы поместила следующие значения, в их нижеуказанном порядке, в таблицу Продавцов:city —namecommcnumSan Jose,— Bianco,— NULL,— 1100.2. Напишите команду, которая бы удалила все порядки заказчика Clemens из таблицыПорядков.3. Напишите команду, которая бы увеличила оценку всех заказчиков в Риме на 100.4.
Продавец Serres оставил компанию. Переназначьте его заказчиков продавцуMotika.(См. Приложение A для ответов.)16ИСПОЛЬЗОВАНИЕПОДЗАПРОСОВ СКОМАНДАМИМОДИФИКАЦИИВ ЭТОЙ ГЛАВЕ, ВЫ УЗНАЕТЕ КАК ИСПОЛЬЗОВАТЬ подзапросы в командах модификации.Вы найдете, что нечто подобное вы уже видели при использовании подзапросовв запросах. Понимание, как подзапросы используются в командах SELECT, cделаетих применение в командах модификации более уверенным, хотя и останутся некоторые вопросы. Завершением команды SELECT является подзапрос, но не предикат, ипоэтому его использование отличается от использования простых предикатов с командами модификации, которые вы уже выполняли ранеее с командами UPDATE иDELETE.
Вы использовали простые запросы чтобы производить значения дляINSERT, а теперь мы можем расширить эти запросы чтобы включять в них подзапросы.Важный принцип, который надо соблюдать при работе с командами модификации, состоит в том, что вы не можете в предложении FROM любого подзапроса модифицировать таблицу, к которой ссылаетесь с помощью основной команды. Этоотносится ко всем трем командам модификации. Хотя имеется большое количествоситуаций, в которых будет полезно сделать запрос той таблицы, которую вы хотитемодифицировать, причем во время ее модификации, это слишком усложняет операцию, чтобы использовать ее на практике.Не делайте ссылки к текущей строке таблицы, указанной в команде, которая является соотнесенным подзапросом.ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С INSERTINSERT — это самый простой случай.
Вы уже видели как вставлять результатызапроса в таблицу. Вы можете использовать подзапросы внутри любого запроса, который генерирует значения для команды INSERT тем же самым способом, которымвы делали это для других запросов — т.е. внутри предиката или предложенияHAVING.Предположим, что мы имеем таблицу с именем SJpeople, столбцы которой совпадают со столбцами нашей таблицы Продавцов. Вы уже видели как заполнять таблицу подобно этой, заказчиками в городе, например, в San Jose:INSERT INTO SjpeopleSELECT *FROM SalespeopleWHERE city = 'San Jose';Теперь мы можем использовать подзапрос чтобы добавить к таблице SJpeopleвсех продавцов которые имеют заказчиков в San Jose, независимо от того, находятсяли там продавцы или нет:INSERT INTO SjpeopleSELECT *FROM SalespeopleWHERE snum = ANY ( SELECT snumFROM CustomersWHERE 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 (SamecitySELECT *FROM (Salespeople outerWHERE city IN ( SELECT cityFROM Customers innerWHERE inner.snum = outer.snum );Ни таблица Samecity, ни таблица Продавцов не должны быть использованы вовнешних или внутренних запросах INSERT.В качестве другого примера, предположим, что вы имеете премию для продавцакоторый имеет самый большой порядок на каждый день.
Вы следите за ним в таблицес именем Bonus, которая содержит поле snum продавцов, поле odate и поле amt. Выдолжны заполнить эту таблицу информацией которая хранится в таблице Порядков,используя следующую команду:INSERT INTO BonusSELECT snum, odate, amtFROM Orders aWHERE amt = ( SELECT MAX (amt)FROM Orders bWHERE a.odate = b.odate );Даже если эта команда имеет подзапрос, который базируется на той же самойтаблице, что и внешний запрос, он не ссылается к таблице Bonus, на которую воздействует команда.