2008 г.
Базы данных. Вводный курс
Сергей Кузнецов
Назад Содержание Вперёд
Лекция 21. Средства манипулирования данными
21.1. Введение
Базы данных, по крайней мере, в приложениях категории OLTP, являются высоко динамичными объектами. В таких приложениях на две операции выборки данных в среднем приходится одна операция обновления содержимого базы данных (добавления новых данных, удаления или модификации существующих данных). Поэтому для пользователей и разработчиков OLTP-приложений средства манипулирования данными по важности находятся на втором месте после средств выборки данных.
В этой лекции мы обсудим средства манипулирования данными, входящие в прямой SQL. Заметим, что с практической точки зрения более важными являются средства манипулирования данными, выходящие за пределы прямого SQL и присутствующие во встраиваемом и динамическом SQL. Но, как мы неоднократно отмечали, в этом курсе мы не обсуждаем возможности использования SQL для создания приложений. По мнению автора, материал данной лекции полезен для общего понимания специфики операторов манипулирования данными, а расширения этих операторов, присутствующие во встраиваемом и динамическом SQL, в любом случае нужно изучать совместно с другими аспектами подобных уровней языка.
Лекция состоит из трех основных разделов. В разделе 21.2. Базовые средства манипулирования данными мы обсудим синтаксис и семантику операторов манипулирования данными, полагая, что они действуют над базовыми таблицами. В разделе 21.3. Представления, над которыми возможны операции обновления будет продемонстрировано, что в ряде случаев, специфицированных в стандарте языка SQL, операторы манипулирования данными можно применять к порождаемым таблицам и представлениям с однозначным отображением результатов действия этих операторов на соответствующие базовые таблицы. Раздел 21.4. Операции обновления баз данных и механизм триггеров посвящен механизму триггеров, которые, по существу, представляют собой «хранимые процедуры», автоматически вызываемые при возникновении соответствующих условий. Триггеры не обязательно связываются с действиями, производимыми при манипулировании данных, но, поскольку одно из основных функций этого механизма состоит в поддержании целостности баз данных, как правило, такая связь имеется. Поэтому мы включили обсуждение механизма триггеров в соответствии со стандартом SQL именно в данную лекцию.
21.2. Базовые средства манипулирования данными
К базовым средствам манипулирования данными языка SQL относятся «поисковые» варианты операторов UPDATE и DELETE. Эти варианты называются поисковыми, потому что при задании соответствующей операции задается логическое условие, налагаемое на строки адресуемой оператором таблицы, которые должны быть подвергнуты модификации или удалению. Кроме того, в такую категорию языковых средств входит оператор INSERT, позволяющий добавлять строки в существующие таблицы. Логично начать изложение именно с оператора INSERT, поскольку, для того чтобы можно было что-либо модифицировать в таблицах или удалять из таблиц, нужно, чтобы в таблицах содержались какие-то строки.
21.2.1. Оператор INSERT для вставки строк в существующие таблицы
Общий синтаксис оператора INSERT выглядит следующим образом:
INSERT INTO table_name
{ [ (column_commalist) ] query_expression
| DEFAULT VALUES
На вид синтаксические правила кажутся очень простыми, пока не вспомнишь, что обозначает синтаксическая категория query_expression (см. подраздел 17.2.1. «Общие синтаксические правила построения скалярных выражений» лекции 17). Даже если ограничиться простейшей составляющей этой конструкции (simple_table), то мы имеем следующие возможности:
simple_table ::= query_specification
| table_value_constructor
| TABLE table_name
Вставка всех строк указанной таблицы
Тем самым, стандарт допускает вставку в указанную таблицу всех строк некоторой другой таблицы (вариант table_name). Эта другая таблица может быть как базовой, так и представляемой. Естественно, что в последнем случае в определении представления не должны присутствовать ссылки на таблицу, в которую производится вставка. При использовании данного варианта оператора вставки число столбцов вставляемой таблицы должно совпадать с числом столбцов таблицы, в которую производится вставка, или с числом столбцов, указанных в списке column_commalist, если этот список задан. Типы данных соответствующих столбцов вставляемой таблицы и таблицы, в которую производится вставка, должны быть совместимыми. Если в операции задан список column_commalist и в нем содержатся не все имена столбцов таблицы, в которую производится вставка, то в оставшиеся столбцы во всех строках заносятся значения столбцов по умолчанию. Если для какого-либо из оставшихся столбцов значение по умолчанию не определено, при выполнении операции вставки фиксируется ошибка.
Чтобы привести пример этого варианта операции INSERT (пример 21.1), предположим, что в базе данных EMP-DEPT-PRO имеется еще одна промежуточная таблица EMP_TEMP, в которой временно хранятся данные о служащих, проходящих испытательный срок. Пусть эта таблица имеет следующий заголовок:
EMP_TEMP:EMP_NO : EMP_NO |
EMP_NAME : VARCHAR |
EMP_BDATE : DATE |
В таблице EMP_TEMP хранятся не полные сведения о служащих, а именно те, которые требуются на время испытательного срока. Если выполнить операцию
INSERT INTO EMP (EMP_NO, EMP_NAME, EMP_BDATE) TABLE EMP_TEMP;
то в основной таблице
EMP появятся строки, соответствующие служащим, проходившим испытательный срок. При этом в столбцах
EMP_NO,
EMP_NAME,
EMP_BDATE этих строк будут содержаться данные, взятые из таблицы
EMP_TEMP, а в столбцах
EMP_SAL,
DEPT_NO,
PRO_NO будут находиться значения, определенные для данных столбцов по умолчанию. Конечно, поскольку столбец
EMP_NO является первичным ключом таблицы
EMP (по всей видимости, и таблицы
EMP_TEMP), операция вставки будет успешно выполнена только в том случае, когда ограничение первичного ключа таблицы
EMP не будет нарушено (конечно же, требуется выполнение и всех других ограничений целостности, определенных для таблицы
EMP).
Вставка явно заданного набора строк
Теперь обратимся к варианту оператора INSERT, в котором набор вставляемых строк задается явно с использованием синтаксической конструкции table_value_constructor. Напомним синтаксические правила, определяющие эту конструкцию:
table_value_constructor ::=
VALUES row_value_constructor_comma_list
row_value_constructor ::= row_value_constructor_element
| [ ROW ] (row_value_constructor_element_comma_list)
| row_subquery
row_value_constructor_element ::= value_expression
| NULL | DEFAULT
Самый простой пример использования этого варианта оператора вставки состоит в занесении в таблицу EMP явно задаваемых данных о новом служащем (пример 21.2):
INSERT INTO EMP
ROW (2445, 'Brown', '1985-04-08', 16500.00, 630, 772);
В этом примере явно заданы значения всех столбцов заносимой строки (как показывают синтаксические правила, ключевое слово ROW можно опустить). Возможен и такой вариант (пример 21.2.1):
INSERT INTO EMP
ROW ( 2445, DEFAULT, NULL, DEFAULT, NULL, NULL);
В этом случае мы знаем о новом служащем очень мало, но уверены в том, что его имя и размер заработной платы должны быть назначены по умолчанию, а про дату рождения, номер отдела и номер проекта ничего не известно. Обратите внимание, что выполнение подобной операции не нарушает ограничения целостности таблицы EMP.
Если обладать полной информацией об определении таблицы EMP, то формулировку операции примера 21.2.1 можно переписать короче следующим эквивалентным образом (пример 21.2.2):
INSERT INTO EMP (EMP_NO) 2445;
Вспомним теперь, что одной из разновидностей value_expression_primary является scalar_subquery (см. раздел 17.2 «Скалярные выражения» лекции 17). Это означает, что в список элементов конструктора строки могут входить скалярные запросы, т. е. запросы, результат выполнения которых состоит из единственной строки, включающей единственный столбец. Поэтому допустима, например, такая операция вставки (пример 21.3):
INSERT INTO EMP VALUES
ROW (2445, (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 2555),
'1985-04-08',
SELECT EMP_SAL
FROM EMP
WHERE EMP_NO = 2555),
NULL, NULL ),
ROW (2446, (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 2556),
'1978-05-09',
(SELECT EMP_SAL
FROM EMP
WHERE EMP_NO = 2556),
NULL, NULL );
После выполнения этой операции в таблице EMP появятся две новые строки для служащих с уникальными идентификаторами 2445 и 2446, причем первому из них будет присвоено имя и размер заработной платы служащего с уникальным идентификатором 2555, а второму – аналогичные данные о служащем с уникальным идентификатором 2556.
Вставка строк результата запроса
Наконец, обсудим вариант оператора вставки, когда набор вставляемых строк определяется через спецификацию запроса. Предположим, например, что требуется сохранить в отдельной таблице DEPT_SUMMARY сведения о числе служащих каждого отдела, их максимальной, минимальной и суммарной заработной плате. Пусть таблица DEPT_SUMMARY уже создана и имеет следующийзаголовок152):
DEPT_SUMMARY:DEPT_NO : DEPT_NO |
DEPT_EMP_NO : INTEGER |
DEPT_MAX_SAL : SALARY |
DEPT_MIN_SAL : SALARY |
DEPT_TOTAL_SAL : SALARY |
Тогда заполнить таблицу можно с помощью следующей операции вставки (пример 21.4):
INSERT INTO DEPT_SUMMARY
(SELECT DEPT_NO, COUNT(*), MAX (EMP_SAL),
MIN (EMP_SAL), SUM (EMP_SAL)
FROM EMP
GROUP BY DEPT_NO);
21.2.2. Оператор UPDATE для модификации существующих строк в существующих таблицах
Общий синтаксис оператора UPDATE выглядит следующим образом:
UPDATE table_name SET update_assignment_commalist
WHERE conditional_expression
update_assignment ::= column_name =
{ value_expression | DEFAULT | NULL }
Семантика оператора модификации существующих строк определяется следующим образом:
- для всех строк таблицы с именем
table_name вычисляется булевское выражение conditional_expression. Строки, для которых значением этого булевского выражения является true, считаются подлежащими модификации (обозначим множество таких строк через Tm); - каждая строка
s (s Tm) подвергается модификации таким образом, что значение каждого столбца этой строки, указанного в списке update_assignment_commalist, заменяется значением, указанным в правой части соответствующего элемента спискамодификации153). Значения столбцов строки s, не указанные в списке модификации, остаются неизменными.
Приведем примеры операций модификации таблиц.
Пример 21.5. Перевести всех служащих, выполняющих проект с номером 772, в отдел 632 и повысить им заработную плату на 1000 руб.
UPDATE EMP SET DEPT_NO = 632, EMP_SAL = EMP_SAL + 1000.00
WHERE PRO_NO = 772;
При выполнении данной операции на первом шаге в таблице EMP будут найдены все строки, относящиеся к служащим, которые участвуют в проекте с номером 772. На втором шаге во всех этих строках значение столбца DEPT_NO будет изменено на 632, а к значению столбца EMP_SAL будет прибавлено 1000.00.
Пример 21.6. Для всех служащих, работающих в отделах, заработная плата менеджеров которых превышает 30000 руб., установить размер заработной платы, на 1000 руб. превышающий средний размер заработной платы соответствующего отдела, а номера проектов, в которых участвуют эти служащие, сделать неопределенными.
UPDATE EMP SET EMP_SAL = (SELECT AVG (EMP1_SAL)
FROM EMP EMP1
WHERE EMP.DEPT_NO = EMP1.DEPT_NO)
+ 1000.00, PRO_NO = NULL
WHERE (SELECT EMP1.EMP_SAL
FROM EMP EMP1, DEPT
WHERE EMP.DEPT_NO = DEPT.DEPT_NO
AND DEPT_MNG = EMP1.EMP_NO AND) > 30000.00;
Конечно, если вам больше нравится другой стиль, то запрос, фигурирующий в разделе WHERE, можно переформулировать с использованием вложенного подзапроса (пример 21.6.1).
UPDATE EMP SET EMP_SAL = (SELECT AVG (EMP1_SAL)
FROM EMP EMP1
WHERE EMP.DEPT_NO = EMP1.DEPT_NO)
+ 1000.00, PRO_NO = NULL
WHERE DEPT.NO IN (SELECT DEPT.DEPT_NO
FROM EMP, DEPT
WHERE DEPT_MNG = EMP_NO
AND EMP_SAL > 30000.00);
Эти примеры позволяют понять, насколько богаты возможности оператора UPDATE. В разделе WHERE может содержаться любое условие, допускаемое в операторе выборки, а в элементах списка раздела SET может присутствовать любой вид value_expression, в том числе любой запрос, вырабатывающий одиночное значение (скалярный подзапрос).
21.2.3. Оператор DELETE для удаления строк в существующих таблицах
Общий синтаксис оператора DELETE выглядит следующим образом:
DELETE FROM table_name
WHERE conditional_expression
В некотором смысле оператор DELETE является частным случаем оператора UPDATE (или, наоборот, действие оператора UPDATE представляет собой комбинацию действий операторов DELETE и INSERT).
Семантика оператора модификации существующих строк определяется следующим образом:
- для всех строк таблицы с именем
table_name вычисляется булевское выражение conditional_expression. Строки, для которых значением этого булевского выражения является true, считаются подлежащими удалению (обозначим множество таких строк через Td); - каждая строка
s (s Td) удаляется из указанной таблицы.
С целью иллюстрации приведем два примера операции удаления строк.
Пример 21.7. Удалить из таблицы EMP все строки, относящиеся к служащим, которые участвуют в проекте с номером 772.
DELETE FROM EMP WHERE PRO_NO = 772;
Пример 21.8. Удалить из таблицы EMP все строки, относящиеся к служащим, размер заработной платы которых превышает размер заработной платы менеджеров их отделов.
DELETE FROM EMP WHERE EMP_SAL >
(SELECT EMP1.EMP_SAL
FROM EMP EMP1, DEPT
WHERE EMP.DEPT_NO = DEPT.DEPT_NO
AND DEPT.DEPT.MNG = EMP1.EMP_NO);
Как и в операторе UPDATE, в разделе WHERE оператора DELETE можно использовать любой вид булевского выражения, допустимого в операторе выборки. Поэтому возможности оператора удаления строк ограничены лишь фантазией пользователя.
152
Мы не будем приводить полное определение таблицы, включающее требуемые ограничения целостности.
153 Если в правой части элемента модификации присутствует value_expression, в котором содержится запрос, то в случае использования в этом запросе имен столбцов модифицируемой таблицы под значениями этих столбцов понимается значение до модификации.
Назад Содержание Вперёд