В значениях, находящихся в правых частях равенств фразы SET, следует уточнять имена используемых столбцов, предваряя их именем таблицы (псевдонима).
Предложение INSERT
Вставка единственной записи в таблицу
Добавить в таблицу Блюда блюдо:
Шашлык (БЛ – 34, Блюдо – Шашлык, В – Г, Основа – Мясо, Выход – 150)
при неизвестной пока трудоемкости приготовления этого блюда.
INSERT
INTO Блюда (БЛ, Блюдо, В, Основа, Выход)
VALUES (34, 'Шашлык', 'Г', 'Мясо', 150);
Создается новая запись для блюда с номером 34, с неопределенным значением в столбце Труд.
Порядок полей в INSERT не обязательно должен совпадать с порядком полей, в котором они определялись при создании таблицы. Вполне допустима и такая версия предыдущего предложения:
INSERT
INTO Блюда (Основа, В, Блюдо, БЛ, Выход)
VALUES ('Мясо', 'Г', 'Шашлык', 34, 150);
При известной трудоемкости приготовления шашлыка (например, 5 коп) сведения о нем можно ввести с помощью укороченного предложения:
INSERT
INTO Блюда
VALUES (34, 'Шашлык', 'Г', 'Мясо', 150, 5);
в котором должен соблюдаться строгий порядок перечисления вводимых значений, так как, не имея перечня загружаемых столб-цов, СУБД может использовать лишь перечень, который определен при создании модифицируемой таблицы.
В предыдущих примерах проводилась модификация стержневой сущности, т.е. таблицы с первичным ключом БЛ. Почти все СУБД имеют механизмы для предотвращения ввода не уникального первичного ключа, например, ввода «Шашлыка» под номером, меньшим 34. А как быть с ассоциациями или другими таблицами, содержащими внешние ключи?
Пусть, например, потребовалось добавить в рецепт блюда Салат летний (БЛ = 1) немного (15 г) лука (ПР = 10), и мы воспользовались предложением
INSERT
INTO Состав (БЛ, ПР, Вес)
VALUES (1, 10, 15);
Подобно операции DELETE операция INSERT может нарушить непротиворечивость базы данных. Если не принять специальных мер, то СУБД не проверяет, имеется ли в таблице Блюда блюдо с первичным ключом БЛ = 1 и в таблице Продукты – продукт с первичным ключом ПР = 10. Отсутствие любого из этих значений породит противоречие: в базе появится ссылка на несуществующую запись. Проблемы, возникающие при использовании внешних ключей, подробно рассмотрены в литературе, а здесь отме-тим, что все «приличные» СУБД имеют механизмы для предотв-ращения ввода записей со значениями внешних ключей, отсутст-вующих среди значений соответствующих первичных ключей.
Вставка множества записей
Создать временную таблицу К_меню, содержащую калорийность и стоимость всех блюд, которые можно приготовить из имеющихся продуктов. (Эта таблица будет использоваться шеф-поваром для составления меню на следующий день.)
Для создания описания временной таблицы можно, например, воспользоваться предложением CREATE TABLE
CREATE TABLE К_меню
( Вид CHAR (10),
Блюдо CHAR (60),
Калор_блюда INTEGER,
Стоим_блюда REAL);
а для ее загрузки данными – предложение INSERT с вложенным подзапросами:
INSERT
INTO К_меню
SELECT Вид, Блюдо,
INT(SUM(((Белки+Углев)*4.1+Жиры*9.3) * Вес/1000)),
(SUM(Стоимость/К_во*Вес/1000) + MIN(Труд/100))
FROM Блюда, Вид_блюд, Состав, Продукты, Наличие
WHERE Блюда.БЛ = Состав.БЛ
AND Состав.ПР = Продукты.ПР
AND Состав.ПР = Наличие.ПР
AND Блюда.В = Вид_блюд.В
AND БЛ NOT IN
( SELECT БЛ
FROM Состав
WHERE ПР IN
( SELECT ПР
FROM Наличие
WHERE К_во = 0))
GROUP BY Вид, Блюдо
ORDER BY Вид, 3;
В этом запросе предложение SELECT выполняется так же, как обычно, но результат не выводится на экран, а копируется в таблицу К_меню. Теперь с этой копией можно работать как с обычной базовой таблицей (Блюда, Про-дукты,…), т.е. выбирать из нее даннные на экран или принтер, обновлять в ней данные и т.п. Никакая из этих операций не будет оказывать влияния на исходные данные (например, изменение в ней названия блюда Салат летний на Салат весенний не приведет к подобному изменению в таблице Блюда, где сохранится старое название). Так как это может привести к противоречиям, то подобные временные таблицы уничтожают после их использования. Поэтому программа, обслуживающая шеф-повара, должна исполнять предложение DROP TABLE К_меню после того, как будет закончено составление меню.
Использование INSERT…SELECT для построения внешнего соединения
Рассмотренное в естественное соединение двух таблиц не включает тех строк какой-либо из них, для которых нет соответствующих строк в другой таблице. Например, если в таблицу Блюда были занесены под номером 34 сведения о Шашлыке, а рецепт его приготовления не был занесен в таблицу Рецепты, то при загрузке их естественного соединения в таблицу Временная:
CREATE TABLE Временная
( Вид CHAR (8),
Блюдо CHAR (60),
Рецепт CHAR (560));
INSERT
INTO Временная
SELECT Вид, Блюдо, Рецепт
FROM Блюда, Рецепты, Вид_блюд
WHERE Блюда.БЛ = Рецепты.БЛ
AND Блюда.В = Вид_блюд.В;
в ней не окажется строки с Шашлыком (в таблице Рецепты не обнаружен код 34, и строка с этим кодом исключена из результата).
Следовательно, в некотором смысле можно считать, что при обычном соединении теряется информация для таких несоответствующих строк. Однако иногда (как и в приведенном примере) может потребоваться способность сохранить эту информацию. В этом случае можно воспользоваться так называемым внешним соединением:
INSERT
INTO Временная
SELECT Вид, Блюдо, Рецепт
FROM Блюда, Рецепты, Вид_блюд
WHERE Блюда.БЛ = Рецепты.БЛ
AND Блюда.В = Вид_блюд.В;
INSERT
INTO Временная
SELECT Вид, Блюдо, «???»
FROM Блюда, Вид_блюд
WHERE Блюда.В = Вид_блюд.В
AND БЛ NOT IN
( SELECT БЛ
FROM Рецепты);
В результате будет создана базовая таблица
Вид | Блюдо | Рецепт | ||
Закуска | Салат летний | Помидоры и яблоки нарезать… | ||
Закуска | Салат мясной | Вареное охлажденное мясо, … | ||
. . . | ||||
Напиток | Кофе черный | Кофеварку или кастрюлю спо… | ||
Напиток | Кофе на молоке | Сварить черный кофе, как … | ||
Горячее | Шашлык | ??? |
где первые 33 строки соответствуют первому INSERT и представляют собой проекцию естественного соединения таблиц Блюда и Рецепты по кодам блюд (БЛ), включающую три столбца. Последняя строка результата соответствует второму INSERT и сохраняет информацию о блюде Шашлык, рецепт котого пока не введен в таблицу Рецепты.
Заметим, что для внешнего соединения нужны два отдельных INSERT…SELECT. Однако тот же результат можно получить и одним INSERT…SELECT, используя фразу UNION, объединяющую предложения SELECT из двух INSERT:
INSERT
INTO Временная
SELECT Вид, Блюдо, Рецепт
FROM Блюда, Рецепты, Вид_блюд
WHERE Блюда.БЛ = Рецепты.БЛ
AND Блюда.В = Вид_блюд.В
UNION
SELECT Вид, Блюдо, «???»
FROM Блюда, Вид_блюд
WHERE Блюда.В = Вид_блюд.В
AND БЛ NOT IN
( SELECT БЛ
FROM Рецепты);
Предложение UPDATE
Обновление единственной записи
Изменить название блюда с кодом БЛ=5 на Форшмак, увеличить его выход на 30 г и установить NULL-значение в столбец Труд.
UPDATE Блюда
SET Блюдо = 'Форшмак', Выход = (Выход+30), Труд = NULL
WHERE БЛ = 5;
Обновление множества записей
Утроить цену всех продуктов таблицы поставки (кроме цены кофе – ПР = 17).
UPDATE Поставки
SET Цена = Цена * 3
WHERE ПР <> 17;
Обновление с подзапросом
Установить равной нулю цену и К_во продуктов для поставщиков из Паневежиса и Резекне.
UPDATE Поставки
SET Цена = 0, К_во = 0
WHERE ПС IN
(SELECT ПС
FROM Поставщики
WHERE Город IN ('Паневежис', 'Резекне'));
Обновление нескольких таблиц
Изменить номер продукта ПР = 13 на ПР = 20.
UPDATE Продукты UPDATE Состав
SET ПР = 20 SET ПР = 20
WHERE ПР = 13; WHERE ПР = 13;
UPDATE Поставки UPDATE Наличие
SET ПР = 20 SET ПР = 20
WHERE ПР = 13; WHERE ПР = 13;
К сожалению в единственным запросе невозможно обновить более одной таблицы, а так как код продукта входит в четыре таблицы, то пришлось выдать четыре сходных запроса. Это может привести к противоречию базы данных (нарушению целостности по ссылкам), поскольку после выполнения первого предложения таблицы Состав, Поставки и Наличие ссылаются на уже несуществующий продукт. База становится непротиворечивой только после выполнения четвертого запроса.
О конструировании предложений модификации
Для тех, кто достаточно хорошо понял предложение SELECT, несложно овладеть конструированием предложений DELETE, INSERT и UPDATE. Но в процессе такого конструирования следует учитывать, что:
1. Если в WHERE фразе предложений DELETE и UPDATE используется вложенный подзапрос, то во фразе FROM этого подзапроса не должна упоминаться таблица, из которой удаляются (в которой обновляются) строки. Аналогично, в подзапросе предложения INSERT не должна упоминаться таблица, в которую загружаются данные.
Так, SQL отвергнет предложение
INSERT
INTO Выбрано
SELECT (33), Т, БЛ
FROM Выбрано
WHERE СМ = 17;
позволяющее ввести информацию о том, что отдыхающий, сидящий на 33-м месте, выбирает тот же набор блюд, что и отдыхающий, сидящий на 17-м месте. Ввод придется осуществить через какую-либо промежуточную таблицу, например, таблицу Выбор:
DELETE
FROM Выбор;
INSERT
INTO Выбор (СМ, Т, БЛ)
SELECT (33), Т, БЛ
FROM Выбрано
WHERE СМ = 17;
INSERT
INTO Выбрано
SELECT СМ, Т, БЛ
FROM Выбор;
2. Составляя предложения модификации данных, необходимо все время помнить о сохранении непротиворечивости базы данных. Об этом упоминалось ранее и подробно говорилось в литературе.