Базы данных, по крайней мере, в приложениях категории
В этой лекции мы обсудим средства манипулирования данными, входящие в прямой SQL. Заметим, что с практической точки зрения более важными являются средства манипулирования данными, выходящие за пределы прямого SQL и присутствующие во встраиваемом и динамическом SQL. Но, как мы неоднократно отмечали, в этом курсе мы не обсуждаем возможности использования SQL для создания приложений. По мнению автора, материал данной лекции полезен для общего понимания специфики операторов манипулирования данными, а расширения этих операторов, присутствующие во встраиваемом и
Лекция состоит из трех основных разделов. В первом разделе мы обсудим синтаксис и семантику операторов манипулирования данными, полагая, что они действуют над
К базовым средствам манипулирования данными языка SQL относятся "поисковые" варианты операторов и . Эти варианты называются поисковыми, потому что при задании соответствующей операции задается логическое условие, налагаемое на строки адресуемой оператором таблицы, которые должны быть подвергнуты модификации или удалению. Кроме того, в такую категорию языковых средств входит оператор , позволяющий добавлять строки в существующие таблицы. Логично начать изложение именно с оператора , поскольку, для того чтобы можно было что-либо модифицировать в таблицах или удалять из таблиц, нужно, чтобы в таблицах содержались какие-то строки.
Общий синтаксис оператора выглядит следующим образом:
INSERT INTO table_name
{ [ (column_commalist) ] query_expression
| DEFAULT VALUES
На вид синтаксические правила кажутся очень простыми, пока не вспомнишь, что обозначает синтаксическая категория query_expression (см. раздел "Общие синтаксические правила построения simple_table ), то мы имеем следующие возможности:
simple_table ::= query_specification
| table_value_constructor
| TABLE table_name
Тем самым, стандарт допускает table_name ). Эта другая таблица может быть как базовой, так и представляемой. Естественно, что в последнем случае в определении column_commalist, если этот column_commalist и в нем содержатся не все имена столбцов таблицы, в которую производится вставка, то в оставшиеся столбцы во всех строках заносятся значения столбцов по умолчанию. Если для какого-либо из оставшихся столбцов значение по умолчанию не определено, при выполнении операции вставки фиксируется ошибка.
Чтобы привести пример этого варианта операции
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_NO, EMP_NAME, EMP_BDATE этих строк будут содержаться данные, взятые из таблицы EMP_TEMP, а в столбцах EMP_SAL, DEPT_NO, PRO_NO будут находиться значения, определенные для данных столбцов по умолчанию. Конечно, поскольку столбец EMP_NO является (по всей видимости, и таблицы EMP_TEMP ), операция вставки будет успешно выполнена только в том случае, когда не будет нарушено (конечно же, требуется выполнение и всех других ).
Теперь обратимся к варианту оператора , в котором 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
Самый простой пример использования этого варианта оператора вставки состоит в занесении в таблицу
INSERT INTO EMP ROW (2445, 'Brown', '1985-04-08', 16500.00, 630, 772);
В этом примере явно заданы значения всех столбцов заносимой строки (как показывают синтаксические правила, ключевое слово
INSERT INTO EMP ROW ( 2445, DEFAULT, NULL, DEFAULT, NULL, NULL);
В этом случае мы знаем о новом служащем очень мало, но уверены в том, что его имя и размер .
Если обладать полной информацией об определении таблицы , то формулировку операции примера 17.2a можно переписать короче следующим эквивалентным образом (пример 17.2b):
INSERT INTO EMP (EMP_NO) 2445;
Вспомним теперь, что одной из разновидностей value_expression_primary является scalar_subquery (см. раздел "
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 );
После выполнения этой операции в таблице появятся две новые строки для служащих с уникальными идентификаторами 2445 и 2446, причем первому из них будет присвоено имя и размер 2555, а второму - аналогичные данные о служащем с уникальным идентификатором 2556.
Наконец, обсудим вариант оператора DEPT_SUMMARY сведения о числе служащих каждого отдела, их максимальной, минимальной и суммарной DEPT_SUMMARY уже создана и имеет следующий
DEPT_NO : DEPT_NO |
DEPT_EMP_NO : INTEGER |
DEPT_MAX_SAL : SALARY |
DEPT_MIN_SAL : SALARY |
DEPT_TOTAL_SAL : SALARY |
Тогда заполнить таблицу можно с помощью следующей операции вставки (пример 17.4):
INSERT INTO DEPT_SUMMARY
(SELECT DEPT_NO, COUNT(*), MAX (EMP_SAL),
MIN (EMP_SAL), SUM (EMP_SAL)
FROM EMP
GROUP BY DEPT_NO);
Общий синтаксис оператора выглядит следующим образом:
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, заменяется значением, указанным в правой части соответствующего элемента списка value_expression, в котором содержится запрос, то в случае использования в этом запросе имен столбцов s, не указанные в списке модификации, остаются неизменными.Приведем примеры операций модификации таблиц.
UPDATE EMP SET DEPT_NO = 632, EMP_SAL = EMP_SAL + 1000.00 WHERE PRO_NO = 772;
При выполнении данной операции на первом шаге в таблице будут найдены все строки, относящиеся к служащим, которые участвуют в проекте с номером 772. На втором шаге во всех этих строках значение столбца DEPT_NO будет изменено на 632, а к значению столбца EMP_SAL будет прибавлено 1000.00.
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) > 30000.00;
Конечно, если вам больше нравится другой стиль, то запрос, фигурирующий в разделе WHERE, можно переформулировать с использованием вложенного
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);
Эти примеры позволяют понять, насколько богаты возможности оператора . В разделе WHERE может содержаться любое условие, допускаемое в операторе выборки, а в элементах списка раздела SET может присутствовать любой вид value_expression, в том числе любой запрос, вырабатывающий одиночное значение (
Общий синтаксис оператора выглядит следующим образом:
DELETE FROM table_name WHERE conditional_expression
В некотором смысле оператор является частным случаем оператора (или, наоборот, действие оператора представляет собой комбинацию действий операторов и ).
Семантика оператора модификации существующих строк определяется следующим образом:
table_name вычисляется conditional_expression. Строки, для которых значением этого true, считаются подлежащими удалению (обозначим множество таких строк через Td );s ( s Td ) удаляется из указанной таблицы.С целью иллюстрации приведем два примера операции удаления строк.
DELETE FROM EMP WHERE PRO_NO = 772;
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);
Как и в операторе , в разделе WHERE оператора можно использовать любой вид
В разделе "Общие синтаксические правила построения VIEW ). Кратко повторим, что
create_view ::= CREATE [ RECURSIVE ] VIEW table_name
[ column_name_comma_list ]
AS query_expression
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
В операциях выборки к любому
Напомним, что FROM которого прямо или косвенно присутствует имя
Если допустить
Поскольку базовым элементом выражения запросов является спецификация запроса, прежде всего нужно понять, какой класс спецификаций запросов является допускающим операции обновления (термин updatable - обновляемый, используемый в стандарте SQL, кажется не слишком удачным в русском варианте). В стандарте SQL/92 спецификация запроса считалась
SELECT DISTINCT (т.е. не требуется удаление строк-дубликатов из результата запроса);SELECT являются именами столбцов, и ни одно имя столбца не встречается в этом списке более одного раза;FROM присутствует только одна ссылка на таблицу, и она указывает либо на базовую таблицу, либо на порождаемую таблицу, допускающую операции обновления;FROM, не встречаются в разделе FROM ни одного WHERE GROUP BY и HAVING.Нетрудно убедиться в том, что эти требования являются достаточными для однозначной интерпретации
SELECT EMP_SAL
FROM (SELECT EMP_SAL, DEPT_NO
FROM EMP
WHERE EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425))
WHERE DEPT_NO <> 630;
Эту спецификацию можно упростить до эквивалентной .
SELECT EMP_SAL
FROM EMP
WHERE EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425 )
AND DEPT_NO <> 630;
Предположим, что с данной спецификацией запроса связано EMPSAL. Тогда операция
UPDATE EMPSAL SET EMP_SAL = EMP_SAL - 1000.00;
UPDATE EMP SET EMP_SAL = EMP_SAL - 1000.00
WHERE EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425 )
AND DEPT_NO <> 630;
Операция
DELETE FROM EMPSAL WHERE EMP_SAL > 20000.00;
DELETE EMPSAL
WHERE EMP_SAL > 20000.00 AND
EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425 )
AND DEPT_NO <> 630;
Операция вставки над EMPSAL
INSERT INTO EMPSAL 25000.00;
трактуется как
INSERT INTO EMP ROW (DEFAULT, DEFAULT, DEFAULT, 25000.00, DEFAULT, DEFAULT);
Понятно, что такая операция будет отвергнута системой, потому что для столбца EMP_NO таблицы значения по умолчанию не определены (это
С другой стороны, условия EMPMNG, определенным над спецификацией запроса ("выбрать данные о служащих, являющихся руководителями отделов").
SELECT *
FROM EMP
WHERE EXISTS (SELECT *
FROM DEPT
WHERE DEPT_MNG = EMP_NO);
можно было бы совершенно корректно выполнять операции обновления (с некоторыми оговорками насчет операции вставки; см. ниже в этом разделе).
В
Введены понятия
SELECT DISTINCT ;SELECT, состоящий из ссылки на некоторый столбец, не может присутствовать в этом списке более одного раза;GROUP BY и HAVING.Если выражение запросов отвечает условиям FROM присутствует только одна ссылка на таблицу, то к каждому столбцу выражения запроса, соответствующему одному столбцу таблицы из раздела FROM, FROM присутствуют две или более ссылки на таблицы, то
FROM ;Другими словами, к столбцу таблицы, которая отвечает условиям
FROM выражения запросов содержится ссылка только на одну таблицу, и все столбцы выражения запросов удовлетворяют условию
FROM ), удовлетворяет условию , и EXCEPT INSERT, см. следующую лекцию).
Приведенный набор правил является достаточно грубым. В
S обозначает некоторое множество столбцов таблицы T, а SS обозначает некоторое подмножество S. Тогда по первой SSS . В терминологии SQL:1999 эта FD называется C1 T1 (порождаемой таблицы или C2 некой другой (базовой или виртуальной) таблицы T2, на основе которой порождается T1, то C1 является двойником C2 . Более точно, C1 является двойником C2 в соответствии с таблицей T2.S1 T1 определяется (путем отображения "один-в-один") множеством столбцов S2 определяющей таблицы T2, и каждый столбец из множества S1 является двойником соответствующего столбца из множества S2, то S1 называется двойником S2 в соответствии с таблицей T2.S1 и S2, такие, что S1S2, S1S2, и S2 является S1 является На основе этих определений в
UCL CT обозначает все множество столбцов этой таблицы, то FD UCLCT представляет собой NATURAL JOIN ) или соединения c заданием списка имен столбцов, значения которых должны совпадать ( USING ), то понятно, что соединенная таблица будет содержать двойников из одной или двух исходных таблиц. Если обозначить через S некоторое множество столбцов результирующей таблицы, а через CT - все множество столбцов этой таблицы, то S является S не допускаются неопределенные значения, и FD SCT является В стандарте определяется несколько правил, на основе которых устанавливаются SLCC список следующих выражений (элемент списка соответствует общему столбцу):
COALESCE (V1, V2) см. в разделе "Средства определения, изменения и ликвидации
Пусть JT обозначает ключевые слова, определяющие тип соединения ( INNER, LEFT, RIGHT, FULL и т.д.), и пусть TN1 и TN2 обозначают имена таблиц или (если они заданы) имена псевдонимов двух таблиц-источников соответственно. Обозначим через IR результат вычисления следующего выражения запросов:
SELECT SLCC, T1*, T2* FROM T1 JT
Тогда, в соответствии с правилами SQL, дополнительными
JT задает INNER или LEFT, то действует FD COALESCE (T1.Ci, T2.Ci)T1.Ci для всех i от единицы до числа столбцов в IR ;JT задает INNER или RIGHT, то действует FD COALESCE (T1.Ci, T2.Ci)T2.Ci для всех i от единицы до числа столбцов в IR.Обозначим через некоторый список выборки. Пусть:
SL совпадает с SLCC ;SL состоит из списка столбцов первой таблицы-источника, за которым следует список столбцов второй таблицы-источника;SL состоит из SLCC, за которым следует список необщих столбцов второй таблицы-источника;SL состоит из SLCC, за которым следует список не общих столбцов первой таблицы-источника;SL состоит из SLCC, за которым следует список необщих столбцов первой таблицы-источника, а далее располагается список не общих столбцов второй таблицы-источника.Тогда, в соответствии со стандартом,
SELECT
FROM. Описывая общую семантику оператора выборки, мы отмечали, что на первом шаге выполнения этого оператора производится (виртуальная) таблица, являющаяся расширенным FROM. Поэтому в стандарте SQL естественным образом формулируются следующие правила. Если в списке ссылок на FROM содержится всего одна ссылка, то FROM содержатся две или более ссылки на таблицы, то, в соответствии со стандартом, FROM.WHERE. В стандарте содержится набор правил, позволяющих определить WHERE входят все строки результата раздела FROM, для которых результатом вычисления логического условия раздела WHERE является true .AND.GROUP BY. Для определения HAVING. HAVING получаются из соответствующих множеств и FD таблицы, к которой применяется этот HAVING подается результат раздела GROUP BY, если этот раздел присутствует в WHERE, если этот раздел присутствует в FROM .HAVING (как и в случае условия раздела WHERE, в данных правилах учитываются операции сравнения по равенству и AND ).SELECT. На определение value_expression ), отличных от ссылок на столбцы.UNION , INTERSECT и EXCEPT. В стандарте отсутствуют какие-либо правила для определения Пусть в базе данных имеется упрощенная таблица , содержащая следующее множество строк (как в примере с GROUP BY ROLLUP разделе "Возможности формулирования аналитических запросов" лекции 16).
Предположим, что в базе данных имеется RICH_EMP, определенное следующим образом:
EMP_NO
|
DEPT_NO
|
EMP_BDATE
|
EMP_SAL
|
|---|---|---|---|
| 2440 | 1 | 1950 | 15000.00 |
| 2441 | 1 | 1950 | 16000.00 |
| 2442 | 1 | 1960 | 14000.00 |
| 2443 | 1 | 1960 | 19000.00 |
| 2444 | 2 | 1950 | 17000.00 |
| 2445 | 2 | 1950 | 16000.00 |
| 2446 | 2 | 1960 | 14000.00 |
| 2447 | 2 | 1960 | 20000.00 |
| 2448 | 3 | 1950 | 18000.00 |
| 2449 | 3 | 1950 | 13000.00 |
| 2450 | 3 | 1960 | 21000.00 |
| 2451 | 3 | 1960 | 22000.00 |
CREATE VIEW RICH_EMP AS
SELECT *
FROM EMP
WHERE EMP_SAL > 18000.00;
Понятно, что в соответствии с правилами SQL (и содержится строка, которая соответствует служащему с номером 2447, получающему зарплату в размере 20000 руб. Естественно, эта строка будет присутствовать в RICH_EMP. Поэтому можно было бы выполнить, например, операцию
UPDATE RICH_EMP SET EMP_SAL = EMP_SAL - 3000 WHERE EMP_NO = 4452;
Но если выполнение такой операции действительно допускается, то в результате строка, соответствующая служащему с номером 2447, исчезнет из RICH_EMP! Аналогичный эффект возникнет при выполнении операции вставки
INSERT INTO RICH_EMP (EMP_NO) 2452;
В появится строка, в которой значением столбца EMP_NO будет 2452, а значения остальных столбцов будут установлены по умолчанию. В частности, значением столбца EMP_SAL будет 10000.00. Тем самым, если подобная операция вставки действительно допустима, то мы вставили в RICH_EMP строку, которую в этой
Чтобы избежать такого противоречивого поведения представляемых таблиц, нужно включать в определение . При наличии этого раздела до реального выполнения операций модификации или вставки строк через ) условие выборки, содержащееся в выражении запросов
Вспомним теперь, что в полном виде синтаксис раздела может включать ключевые слова или . Обсудим их смысл. Предположим, что V2 определяется над V1 следующим образом:
CREATE VIEW V2 AS SELECT ... FROM V1 WHERE ... [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
Пусть над V2 выполняется некоторая операция O обновления базы данных. Тогда:
V2 определялось без раздела WITH CHECK OPTION , то при выполнении операции O будут проверяться все условия, определяющие V1 (если в определении V1 присутствовал раздел WITH CHECK OPTION ), но никаким образом не будут учитываться условия выборки, содержащееся в выражении запросов V2 ;V2 содержался раздел WITH LOCAL CHECK OPTION, то при выполнении операции O будут проверяться все условия, определяющие V1, и все условия, содержащееся в выражении запросов V2 ;V2 содержался раздел WITH CASCADED CHECK OPTION, то при выполнении операции O будут проверяться все условия, определяющие V1 (так, как если бы в определении V1 присутствовал раздел WITH CASCADED CHECK OPTION ). Тем самым, будут проверяться все V1 ; все условия всех V2.Чтобы пояснить результаты действия раздела , допустим, что в базе данных присутствуют определения двух MIDDLE_RICH_EMP и MORE_RICH_EMP:
CREATE VIEW MIDDLE_RICH_EMP AS
SELECT *
FROM EMP
WHERE EMP_SAL < 20000.00
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ];
CREATE VIEW MORE_RICH_EMP AS
SELECT *
FROM MIDDLE_RICH_EMP
WHERE EMP_SAL > 18000.00
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ];
Очевидно, что в тело (материализованного) MIDDLE_RICH_EMP будут входить следующие строки :
EMP_NO
|
DEPT_NO
|
EMP_BDATE
|
EMP_SAL
|
|---|---|---|---|
| 2440 | 1 | 1950 | 15000.00 |
| 2441 | 1 | 1950 | 16000.00 |
| 2442 | 1 | 1960 | 14000.00 |
| 2443 | 1 | 1960 | 19000.00 |
| 2444 | 2 | 1950 | 17000.00 |
| 2445 | 2 | 1950 | 16000.00 |
| 2446 | 2 | 1960 | 14000.00 |
| 2448 | 3 | 1950 | 18000.00 |
| 2449 | 3 | 1950 | 13000.00 |
В тело (материализованного) MORE_RICH_EMP будут входить следующие строки представляемой таблицы MIDDLE_RICH_EMP:
EMP_NO
|
DEPT_NO
|
EMP_BDATE
|
EMP_SAL
|
|---|---|---|---|
| 2443 | 1 | 1960 | 19000.00 |
В каждом из MIDDLE_RICH_EMP и MORE_RICH_EMP может отсутствовать или присутствовать (в одном из двух видов) раздел . В совокупности возможен один из девяти случаев:
MORE_RICH_EMP
|
none
|
|
|
|---|---|---|---|
MIDDLE_RICH_EMP
| |||
none |
Случай 1 |
Случай 2 |
Случай 3 |
|
Случай 4 |
Случай 5 |
Случай 6 |
|
Случай 7 |
Случай 8 |
Случай 9 |
Чтобы рассмотреть каждый из возможных случаев по отдельности, обсудим, что будет происходить в каждом случае при выполнении следующих двух операций модификации строк (будем называть эти операции U1 и U2 соответственно MORE_RICH_EMP, неизвестно ограничение EMP_SAL < 20000.00, на котором основывается MIDDLE_RICH_EMP .
UPDATE MORE_RICH_EMP SET EMP_SAL = EMP_SAL + 7000.00; UPDATE MORE_RICH_EMP SET EMP_SAL = EMP_SAL - 7000.00;
Случай 1. Ни в одном из .
Первый неожиданный результат состоит в том, что после выполнения операции U1 тело MORE_RICH_EMP оказывается пустым. Действительно, у единственной строки таблицы (со значением EMP_NO, равным 2443 ), одновременно удовлетворяющей условиям обоих EMP_SAL принимает значение 26000.00. После этого строка перестает удовлетворять условию MIDDLE_RICH_EMP и исчезает из результирующей таблицы MORE_RICH_EMP. Этот результат может быть особенно неожиданным для MORE_RICH_EMP имеет вид EMP_SAL > 18000.00, и соблюдение этого условия должно сохраняться при увеличении размера зарплаты.
Выполнение операции U2 также приведет к опустошению тела MORE_RICH_EMP (в не останется ни одной строки, удовлетворяющей условию этого MORE_RICH_EMP, которым известно условие MIDDLE_RICH_EMP, с удивлением обнаружат в теле результирующей таблицы новые строки.
Случай 2. В определении MIDDLE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION, а в определении MORE_RICH_EMP раздел отсутствует.
В этом случае, в соответствии с первыми двумя правилами проверки корректности выполнения операций обновления над U1 должна быть отвергнута системой (поскольку ее выполнение нарушает условие MIDDLE_RICH_EMP ). Но заметим, что такое поведение системы будет совершенно неожиданным и непонятным для тех MORE_RICH_EMP, поскольку операция U1 явно не может нарушить видимое ими ограничение.
С другой стороны, операция U2 будет успешно выполнена и по-прежнему приведет к опустошению тела результирующей таблицы MORE_RICH_EMP.
Случай 3. В определении MIDDLE_RICH_EMP содержится раздел WITH , а в определении MORE_RICH_EMP раздел отсутствует.
В этой ситуации будут проверяться условия, содержащиеся в определении MIDDLE_RICH_EMP, а также все и всех других U1 будет отвергнута системой, а операция U2 будет "успешно" выполнена. Другими словами, повторится Случай 2.
Случай 4. В определении MIDDLE_RICH_EMP раздел отсутствует, а в определении MORE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION.
Понятно, что в этом варианте операция U2 не сработает (ее выполнение не будет допущено условием "MORE_RICH_EMP ). Но операция U1 (увеличение размера зарплаты служащих) будет успешно выполнена, поскольку она не противоречит локальным ограничениям MORE_RICH_EMP.
Случай 5. В определениях MIDDLE_RICH_EMP и MORE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION.
Выполнение обеих операций U1 и U2 будет справедливо отвергнуто. На первый взгляд все в порядке. Но если над MORE_RICH_EMP будет определено еще одно V, то мы можем получить ситуацию Случая 2, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 6. В определении MIDDLE_RICH_EMP содержится раздел WITH , а в определении MORE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION.
Снова, если над MORE_RICH_EMP будет определено еще одно V, то мы можем попасть в ситуацию Случая 2, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 7. В определении MIDDLE_RICH_EMP раздел отсутствует, а в определении MORE_RICH_EMP содержится раздел WITH .
Если над MORE_RICH_EMP будет определено еще одно V, то мы можем попасть в ситуацию Случая 3, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 8. В определении MIDDLE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION, а в определении MORE_RICH_EMP - раздел WITH .
Если над MORE_RICH_EMP будет определено еще одно V, то мы можем получить ситуацию Случая 3, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 9. В определениях MIDDLE_RICH_EMP и MORE_RICH_EMP содержится раздел WITH .
Только в этом случае операции обновления будут выполняться корректно, независимо от того, имеются ли в базе данных MORE_RICH_EMP или между MORE_RICH_EMP, MIDDLE_RICH_EMP и .
Очевидный вывод из приведенного анализа заключается в том, что единственным способом обеспечить корректность выполнения операций обновления через WITH . В этом случае поведение системы будет оставаться корректным при введении дополнительных MORE_RICH_EMP, между MORE_RICH_EMP и MIDDLE_RICH_EMP или между MIDDLE_RICH_EMP и , если в определениях всех этих WITH .
Завершим обсуждение возможностей применения операций обновления к
Во-первых, как отмечалось в лекции 3, одной из наиболее привлекательных черт
Во-вторых, на первый взгляд задача не является слишком трудной (по крайней мере, если оставаться в пределах
К сожалению, это ощущение простоты проблемы оказалось обманчивым. Было выполнено множество исследований, опубликовано множество статей (нам кажется нецелесообразным приводить список этих статей в данном курсе), но так и не удалось обнаружить полное множество алгебраических выражений, для которых возможна однозначная интерпретация операций обновления. На мой взгляд, данная ситуация оказала заметное влияние на подход к решению проблемы
В двух первых
Кстати, одна из идей, включавшихся в ранние варианты проекта SQL-3, состояла в том, чтобы расширить определение представляемой таблицы средствами, позволяющими явно специфицировать действия, которые нужно предпринимать при выполнении над , и . Другими словами, предлагалось переложить решение проблемы на плечи пользователей СУБД. Конечно, это радикальный подход, но, с другой стороны, он мог бы привести к полной анархии.
Как можно заметить, в официально принятом
Конечно, термин
В стандарте же языка SQL спецификации
Заметим, что
В языке обеспечиваются возможности определения , или , но существует и возможность определения
Можно придумать различные способы полезного применения механизма
DEPT_TOTAL_SAL таблицы DEPT хранится суммарное значение DEPT со значением столбца DEPT_NO, которое соответствует номеру отдела нового служащего.Для более подробного обсуждения
trigger_definition ::=
CREATE TRIGGER trigger_name
{ BEFORE | AFTER }
{ INSERT | DELETE | UPDATE [ OF column_commalist ] }
ON table_name [ REFERENCING
old_or_new_values_alias_list ]
triggered_action
triggered_action ::=
[ FOR EACH { ROW | STATEMENT } ]
[ WHEN left_paren conditional_expression right_paren ]
triggered_SQL_statement
triggered_SQL_statement ::= SQL_procedure_statement
| BEGIN ATOMIC
SQL_procedure_statement_semicolonlist
END
old_or_new_values_alias ::= OLD [ ROW ] [ AS ] correlation_name
| NEW [ ROW ] [ AS ] correlation_name
| OLD TABLE [ AS ] identifier
| NEW TABLE [ AS ] identifier
Естественно, в языке имеется и конструкция, отменяющая определение
.
(Конструкция в языке SQL не поддерживается.)
Как мы видим, синтаксические правила допускают несколько разновидностей определения
Если в определении , то
Выбор одного из этих ключевых слов при определении к срабатыванию или , то число возможных событий, приводящих к срабатыванию
Заметим, что в
Если в определении FOR EACH , то FOR EACH (или явная спецификация FOR EACH отсутствует), то
Включение в определение с соответствующим true. Понятно, что виды и интерпретация , различаются у FOR EACH и у FOR EACH . В первом случае условное выражение вычисляется для одной строки, которая должна быть обновлена данного
triggered_SQL_statement (будем называть ее BEGIN и END.
Недоумение читателей может вызвать неуточненная конструкция
Обсудим теперь, откуда возникает потребность в SQL_procedure_statement чаще всего используются операторы SQL обновления базы данных. Иногда (и мы покажем это на примере) для корректного определения функциональности BEGIN и END ).
Для иллюстрации случая, когда при определении (прием на работу нового служащего). Если значение столбца DEPT_NO в очередной вставляемой строке отлично от NULL, то DEPT_EMP_NO и DEPT_TOTAL_SAL строки таблицы DEPT со значением столбца DEPT_NO, которое соответствует номеру отдела нового служащего (пример 17.10):
CREATE TRIGGER DEPT_CORRECTION AFTER INSERT ON EMP
FOR EACH ROW
WHEN (EMP.DEPT_NO IS NOT NULL)
UPDATE DEPT SET
DEPT_EMP_NO = DEPT_EMP_NO + 1,
DEPT_TOTAL_SAL = DEPT_TOTAL_SAL + EMP_SAL
WHERE DEPT.DEPT_NO = EMP.DEPT_NO;
Теперь предположим, что при увольнении служащего (удалении строки из таблицы
EMP_NO : EMP_NO |
EMP_NAME : VARCHAR |
DEPT_NO : DEPT_NO |
Определение соответствующего
CREATE TRIGGER EMP_DISMISSION AFTER DELETE ON EMP
FOR EACH ROW
BEGIN ATOMIC
INSERT INTO EMP_DISMISSED
ROW (EMP.EMP_NO, EMP.EMP_NAME, EMP.DEPT_NO);
UPDATE DEPT SET
DEPT_EMP_NO = DEPT_EMP_NO - 1,
DEPT_TOTAL_SAL = DEPT_TOTAL_SAL - EMP_SAL
WHERE DEPT.DEPT_NO = EMP.DEPT_NO
END;
При
Обсудим понятие должно поддерживаться правило, в соответствии с которым каждый служащий, становящийся CHANGE_MNG_NO следующим образом:
CREATE TRIGGER CHANGE_MNG_NO AFTER UPDATE OF PRO_MNG ON PRO
FOR EACH ROW
UPDATE EMP SET EMP_SAL = EMP_SAL + 10000.00
WHERE EMP_NO = PRO_MNG;
Но очевидно, что для поддержания корректности данных в таблице DEPT нам требуется EMP_SAL в таблице . Определим соответствующий DEPT_CORRECTION_1:
CREATE TRIGGER DEPT_CORRECTION_1
AFTER UPDATE OF EMP_SAL ON EMP
REFERENCING OLD ROW AS OLD_EMP NEW ROW AS NEW_EMP
FOR EACH ROW
UPDATE DEPT SET
DEPT_TOTAL_SAL =
DEPT_TOTAL_SAL + NEW_EMP.EMP_SAL -
OLD_EMP.EMP_SAL
WHERE EMP.DEPT_NO = DEPT.DEPT_NO;
Пусть теперь выполняется операция
UPDATE PRO SET PRO_MNG = 4455 WHERE PRO_NO = 554;
Сразу после выполнения этой операции сработает CHANGE_MNG_NO. Этот CMN. Заметим, что исходный оператор модификации в действительности изменяет только одну строку таблицы , но CHANGE_MNG_NO это неизвестно, и он будет работать так, как если бы изменялось произвольное число строк таблицы .
Выполнение операции модификации таблицы приведет к срабатыванию DEPT_CORRECTION_1. В этот момент CMN будет "упрятан в стек", образуется и станет активным DR1. После завершения DR1 больше не требуется, и он ликвидируется, а из стека восстанавливается CMN, в котором и будет завершено CHANGE_MNG_NO.
INSERT , UPDATE или DELETE ; UPDATE ); STATEMENT , уже ROW , уже Отслеживание уже
При создании
Мы уже продемонстрировали использование старых и новых значений в определении DEPT_CORRECTION_1. Поскольку эта возможность является важной особенностью языка SQL, обсудим ее более подробно.
Сначала немного поговорим о синтаксисе. Итак, в определении REFERENCING old_or_new_values_alias_list, причем список определений псевдонимов может включать следующие элементы:
OLD [ ROW ] [ AS ] correlation_name NEW [ ROW ] [ AS ] correlation_name OLD TABLE [ AS ] identifier NEW TABLE [ AS ] identifier
Каждая из этих конструкций может входить в список определений псевдонимов не более одного раза, и спецификации OLD и NEW могут присутствовать только в определении . Определяемые корреляционные имена и псевдонимы можно использовать внутри NEW ) или NEW TABLE ), то эти имена можно использовать для ссылок на значения, которые будут существовать в или . Если же определяется корреляционное имя для старых значений ( OLD ) или OLD TABLE ), то данные имена можно использовать для ссылок на значения, которые существовали в или . Конечно, нельзя использовать NEW или NEW TABLE в , поскольку никакие новые значения не создаются. Аналогично, нельзя использовать OLD или OLD TABLE в , поскольку никакие старые значения не существовали.
можно использовать корреляционное имя, определенное в конструкции OLD , для ссылки на значения строки, удаляемой или OLD TABLE, для ссылки на любое значение NEW и NEW TABLE.
Для имеется существенное ограничение: в них не разрешается использовать конструкции OLD TABLE и NEW TABLE, а внутритриггерный SQL-оператор не может производить какие-либо изменения в базе данных. Основанием для такого ограничения является то, что на OLD TABLE и NEW TABLE, могут существенно влиять
В SQL:1999 не запрещается определение нескольких или ) и срабатывающих по одному и тому же событию. Понятно, что при возникновении условия срабатывания всех таких
Решение, принятое в SQL, является предельно простым, хотя и несколько странным. При определении каждого CREATE , и все или ) и срабатывающие по одному и тому же событию, упорядочиваются в соответствии со своими временными метками. Тогда при возникновении условия срабатывания всех
Подход к установлению
И еще одно интересное свойство
В разделе "Введение" лекции 12 мы достаточно подробно обсуждали механизм определения
Конечно,
Однако даже в тех СУБД, где не смешиваются механизмы . Если выполняется некоторая операция обновления таблицы T, то после ее выполнения и срабатывания всех T и видом произведенной операции, а также соответствующие
В заключение этого раздела, посвященного механизму
В этой лекции мы обсудили важные аспекты языка SQL, относящиеся к механизмам обновления данных. В первом разделе были рассмотрены операторы прямого SQL, предназначенные для вставки, модификации и удаления данных из существующих таблиц. Операторы и этой категории иногда называют поисковыми, поскольку в них включаются условия на строки таблицы, которые должны быть модифицированы или удалены. В языке SQL определены так-же позиционные операторы модификации и удаления строк, а также динамические позиционные варианты данных операторов, но для их обсуждения требуется общее рассмотрение встраиваемого и динамического SQL, что выходит за рамки данного курса. На мой взгляд, поисковые версии операторов модификации и удаления хорошо характеризуют соответствующие возможности языка SQL. Кроме того, оператор , представленный в этой лекции, специфицирован в языке SQL только в таком варианте.
Второй раздел лекции посвящен обсуждению возможностей языка SQL, связанных с
Наконец, в третьем разделе лекции рассматривался механизм
Один из основных выводов лекции состоит в том, что в
Часть следующей лекции, относящаяся к средствам языка SQL, которые предназначены для управления транзакциями, также имеет непосредственное отношение к операторам обновления баз данных.
Базы данных, по крайней мере, в приложениях категории
В этой лекции мы обсудим средства манипулирования данными, входящие в прямой SQL. Заметим, что с практической точки зрения более важными являются средства манипулирования данными, выходящие за пределы прямого SQL и присутствующие во встраиваемом и динамическом SQL. Но, как мы неоднократно отмечали, в этом курсе мы не обсуждаем возможности использования SQL для создания приложений. По мнению автора, материал данной лекции полезен для общего понимания специфики операторов манипулирования данными, а расширения этих операторов, присутствующие во встраиваемом и
Лекция состоит из трех основных разделов. В первом разделе мы обсудим синтаксис и семантику операторов манипулирования данными, полагая, что они действуют над
К базовым средствам манипулирования данными языка SQL относятся "поисковые" варианты операторов и . Эти варианты называются поисковыми, потому что при задании соответствующей операции задается логическое условие, налагаемое на строки адресуемой оператором таблицы, которые должны быть подвергнуты модификации или удалению. Кроме того, в такую категорию языковых средств входит оператор , позволяющий добавлять строки в существующие таблицы. Логично начать изложение именно с оператора , поскольку, для того чтобы можно было что-либо модифицировать в таблицах или удалять из таблиц, нужно, чтобы в таблицах содержались какие-то строки.
Общий синтаксис оператора выглядит следующим образом:
INSERT INTO table_name
{ [ (column_commalist) ] query_expression
| DEFAULT VALUES
На вид синтаксические правила кажутся очень простыми, пока не вспомнишь, что обозначает синтаксическая категория query_expression (см. раздел "Общие синтаксические правила построения simple_table ), то мы имеем следующие возможности:
simple_table ::= query_specification
| table_value_constructor
| TABLE table_name
Тем самым, стандарт допускает table_name ). Эта другая таблица может быть как базовой, так и представляемой. Естественно, что в последнем случае в определении column_commalist, если этот column_commalist и в нем содержатся не все имена столбцов таблицы, в которую производится вставка, то в оставшиеся столбцы во всех строках заносятся значения столбцов по умолчанию. Если для какого-либо из оставшихся столбцов значение по умолчанию не определено, при выполнении операции вставки фиксируется ошибка.
Чтобы привести пример этого варианта операции
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_NO, EMP_NAME, EMP_BDATE этих строк будут содержаться данные, взятые из таблицы EMP_TEMP, а в столбцах EMP_SAL, DEPT_NO, PRO_NO будут находиться значения, определенные для данных столбцов по умолчанию. Конечно, поскольку столбец EMP_NO является (по всей видимости, и таблицы EMP_TEMP ), операция вставки будет успешно выполнена только в том случае, когда не будет нарушено (конечно же, требуется выполнение и всех других ).
Теперь обратимся к варианту оператора , в котором 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
Самый простой пример использования этого варианта оператора вставки состоит в занесении в таблицу
INSERT INTO EMP ROW (2445, 'Brown', '1985-04-08', 16500.00, 630, 772);
В этом примере явно заданы значения всех столбцов заносимой строки (как показывают синтаксические правила, ключевое слово
INSERT INTO EMP ROW ( 2445, DEFAULT, NULL, DEFAULT, NULL, NULL);
В этом случае мы знаем о новом служащем очень мало, но уверены в том, что его имя и размер .
Если обладать полной информацией об определении таблицы , то формулировку операции примера 17.2a можно переписать короче следующим эквивалентным образом (пример 17.2b):
INSERT INTO EMP (EMP_NO) 2445;
Вспомним теперь, что одной из разновидностей value_expression_primary является scalar_subquery (см. раздел "
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 );
После выполнения этой операции в таблице появятся две новые строки для служащих с уникальными идентификаторами 2445 и 2446, причем первому из них будет присвоено имя и размер 2555, а второму - аналогичные данные о служащем с уникальным идентификатором 2556.
Наконец, обсудим вариант оператора DEPT_SUMMARY сведения о числе служащих каждого отдела, их максимальной, минимальной и суммарной DEPT_SUMMARY уже создана и имеет следующий
DEPT_NO : DEPT_NO |
DEPT_EMP_NO : INTEGER |
DEPT_MAX_SAL : SALARY |
DEPT_MIN_SAL : SALARY |
DEPT_TOTAL_SAL : SALARY |
Тогда заполнить таблицу можно с помощью следующей операции вставки (пример 17.4):
INSERT INTO DEPT_SUMMARY
(SELECT DEPT_NO, COUNT(*), MAX (EMP_SAL),
MIN (EMP_SAL), SUM (EMP_SAL)
FROM EMP
GROUP BY DEPT_NO);
Общий синтаксис оператора выглядит следующим образом:
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, заменяется значением, указанным в правой части соответствующего элемента списка value_expression, в котором содержится запрос, то в случае использования в этом запросе имен столбцов s, не указанные в списке модификации, остаются неизменными.Приведем примеры операций модификации таблиц.
UPDATE EMP SET DEPT_NO = 632, EMP_SAL = EMP_SAL + 1000.00 WHERE PRO_NO = 772;
При выполнении данной операции на первом шаге в таблице будут найдены все строки, относящиеся к служащим, которые участвуют в проекте с номером 772. На втором шаге во всех этих строках значение столбца DEPT_NO будет изменено на 632, а к значению столбца EMP_SAL будет прибавлено 1000.00.
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) > 30000.00;
Конечно, если вам больше нравится другой стиль, то запрос, фигурирующий в разделе WHERE, можно переформулировать с использованием вложенного
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);
Эти примеры позволяют понять, насколько богаты возможности оператора . В разделе WHERE может содержаться любое условие, допускаемое в операторе выборки, а в элементах списка раздела SET может присутствовать любой вид value_expression, в том числе любой запрос, вырабатывающий одиночное значение (
Общий синтаксис оператора выглядит следующим образом:
DELETE FROM table_name WHERE conditional_expression
В некотором смысле оператор является частным случаем оператора (или, наоборот, действие оператора представляет собой комбинацию действий операторов и ).
Семантика оператора модификации существующих строк определяется следующим образом:
table_name вычисляется conditional_expression. Строки, для которых значением этого true, считаются подлежащими удалению (обозначим множество таких строк через Td );s ( s Td ) удаляется из указанной таблицы.С целью иллюстрации приведем два примера операции удаления строк.
DELETE FROM EMP WHERE PRO_NO = 772;
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);
Как и в операторе , в разделе WHERE оператора можно использовать любой вид
В разделе "Общие синтаксические правила построения VIEW ). Кратко повторим, что
create_view ::= CREATE [ RECURSIVE ] VIEW table_name
[ column_name_comma_list ]
AS query_expression
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
В операциях выборки к любому
Напомним, что FROM которого прямо или косвенно присутствует имя
Если допустить
Поскольку базовым элементом выражения запросов является спецификация запроса, прежде всего нужно понять, какой класс спецификаций запросов является допускающим операции обновления (термин updatable - обновляемый, используемый в стандарте SQL, кажется не слишком удачным в русском варианте). В стандарте SQL/92 спецификация запроса считалась
SELECT DISTINCT (т.е. не требуется удаление строк-дубликатов из результата запроса);SELECT являются именами столбцов, и ни одно имя столбца не встречается в этом списке более одного раза;FROM присутствует только одна ссылка на таблицу, и она указывает либо на базовую таблицу, либо на порождаемую таблицу, допускающую операции обновления;FROM, не встречаются в разделе FROM ни одного WHERE GROUP BY и HAVING.Нетрудно убедиться в том, что эти требования являются достаточными для однозначной интерпретации
SELECT EMP_SAL
FROM (SELECT EMP_SAL, DEPT_NO
FROM EMP
WHERE EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425))
WHERE DEPT_NO <> 630;
Эту спецификацию можно упростить до эквивалентной .
SELECT EMP_SAL
FROM EMP
WHERE EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425 )
AND DEPT_NO <> 630;
Предположим, что с данной спецификацией запроса связано EMPSAL. Тогда операция
UPDATE EMPSAL SET EMP_SAL = EMP_SAL - 1000.00;
UPDATE EMP SET EMP_SAL = EMP_SAL - 1000.00
WHERE EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425 )
AND DEPT_NO <> 630;
Операция
DELETE FROM EMPSAL WHERE EMP_SAL > 20000.00;
DELETE EMPSAL
WHERE EMP_SAL > 20000.00 AND
EMP_NAME = (SELECT EMP_NAME
FROM EMP
WHERE EMP_NO = 4425 )
AND DEPT_NO <> 630;
Операция вставки над EMPSAL
INSERT INTO EMPSAL 25000.00;
трактуется как
INSERT INTO EMP ROW (DEFAULT, DEFAULT, DEFAULT, 25000.00, DEFAULT, DEFAULT);
Понятно, что такая операция будет отвергнута системой, потому что для столбца EMP_NO таблицы значения по умолчанию не определены (это
С другой стороны, условия EMPMNG, определенным над спецификацией запроса ("выбрать данные о служащих, являющихся руководителями отделов").
SELECT *
FROM EMP
WHERE EXISTS (SELECT *
FROM DEPT
WHERE DEPT_MNG = EMP_NO);
можно было бы совершенно корректно выполнять операции обновления (с некоторыми оговорками насчет операции вставки; см. ниже в этом разделе).
В
Введены понятия
SELECT DISTINCT ;SELECT, состоящий из ссылки на некоторый столбец, не может присутствовать в этом списке более одного раза;GROUP BY и HAVING.Если выражение запросов отвечает условиям FROM присутствует только одна ссылка на таблицу, то к каждому столбцу выражения запроса, соответствующему одному столбцу таблицы из раздела FROM, FROM присутствуют две или более ссылки на таблицы, то
FROM ;Другими словами, к столбцу таблицы, которая отвечает условиям
FROM выражения запросов содержится ссылка только на одну таблицу, и все столбцы выражения запросов удовлетворяют условию
FROM ), удовлетворяет условию , и EXCEPT INSERT, см. следующую лекцию).
Приведенный набор правил является достаточно грубым. В
S обозначает некоторое множество столбцов таблицы T, а SS обозначает некоторое подмножество S. Тогда по первой SSS . В терминологии SQL:1999 эта FD называется C1 T1 (порождаемой таблицы или C2 некой другой (базовой или виртуальной) таблицы T2, на основе которой порождается T1, то C1 является двойником C2 . Более точно, C1 является двойником C2 в соответствии с таблицей T2.S1 T1 определяется (путем отображения "один-в-один") множеством столбцов S2 определяющей таблицы T2, и каждый столбец из множества S1 является двойником соответствующего столбца из множества S2, то S1 называется двойником S2 в соответствии с таблицей T2.S1 и S2, такие, что S1S2, S1S2, и S2 является S1 является На основе этих определений в
UCL CT обозначает все множество столбцов этой таблицы, то FD UCLCT представляет собой NATURAL JOIN ) или соединения c заданием списка имен столбцов, значения которых должны совпадать ( USING ), то понятно, что соединенная таблица будет содержать двойников из одной или двух исходных таблиц. Если обозначить через S некоторое множество столбцов результирующей таблицы, а через CT - все множество столбцов этой таблицы, то S является S не допускаются неопределенные значения, и FD SCT является В стандарте определяется несколько правил, на основе которых устанавливаются SLCC список следующих выражений (элемент списка соответствует общему столбцу):
COALESCE (V1, V2) см. в разделе "Средства определения, изменения и ликвидации
Пусть JT обозначает ключевые слова, определяющие тип соединения ( INNER, LEFT, RIGHT, FULL и т.д.), и пусть TN1 и TN2 обозначают имена таблиц или (если они заданы) имена псевдонимов двух таблиц-источников соответственно. Обозначим через IR результат вычисления следующего выражения запросов:
SELECT SLCC, T1*, T2* FROM T1 JT
Тогда, в соответствии с правилами SQL, дополнительными
JT задает INNER или LEFT, то действует FD COALESCE (T1.Ci, T2.Ci)T1.Ci для всех i от единицы до числа столбцов в IR ;JT задает INNER или RIGHT, то действует FD COALESCE (T1.Ci, T2.Ci)T2.Ci для всех i от единицы до числа столбцов в IR.Обозначим через некоторый список выборки. Пусть:
SL совпадает с SLCC ;SL состоит из списка столбцов первой таблицы-источника, за которым следует список столбцов второй таблицы-источника;SL состоит из SLCC, за которым следует список необщих столбцов второй таблицы-источника;SL состоит из SLCC, за которым следует список не общих столбцов первой таблицы-источника;SL состоит из SLCC, за которым следует список необщих столбцов первой таблицы-источника, а далее располагается список не общих столбцов второй таблицы-источника.Тогда, в соответствии со стандартом,
SELECT
FROM. Описывая общую семантику оператора выборки, мы отмечали, что на первом шаге выполнения этого оператора производится (виртуальная) таблица, являющаяся расширенным FROM. Поэтому в стандарте SQL естественным образом формулируются следующие правила. Если в списке ссылок на FROM содержится всего одна ссылка, то FROM содержатся две или более ссылки на таблицы, то, в соответствии со стандартом, FROM.WHERE. В стандарте содержится набор правил, позволяющих определить WHERE входят все строки результата раздела FROM, для которых результатом вычисления логического условия раздела WHERE является true .AND.GROUP BY. Для определения HAVING. HAVING получаются из соответствующих множеств и FD таблицы, к которой применяется этот HAVING подается результат раздела GROUP BY, если этот раздел присутствует в WHERE, если этот раздел присутствует в FROM .HAVING (как и в случае условия раздела WHERE, в данных правилах учитываются операции сравнения по равенству и AND ).SELECT. На определение value_expression ), отличных от ссылок на столбцы.UNION , INTERSECT и EXCEPT. В стандарте отсутствуют какие-либо правила для определения Пусть в базе данных имеется упрощенная таблица , содержащая следующее множество строк (как в примере с GROUP BY ROLLUP разделе "Возможности формулирования аналитических запросов" лекции 16).
Предположим, что в базе данных имеется RICH_EMP, определенное следующим образом:
EMP_NO
|
DEPT_NO
|
EMP_BDATE
|
EMP_SAL
|
|---|---|---|---|
| 2440 | 1 | 1950 | 15000.00 |
| 2441 | 1 | 1950 | 16000.00 |
| 2442 | 1 | 1960 | 14000.00 |
| 2443 | 1 | 1960 | 19000.00 |
| 2444 | 2 | 1950 | 17000.00 |
| 2445 | 2 | 1950 | 16000.00 |
| 2446 | 2 | 1960 | 14000.00 |
| 2447 | 2 | 1960 | 20000.00 |
| 2448 | 3 | 1950 | 18000.00 |
| 2449 | 3 | 1950 | 13000.00 |
| 2450 | 3 | 1960 | 21000.00 |
| 2451 | 3 | 1960 | 22000.00 |
CREATE VIEW RICH_EMP AS
SELECT *
FROM EMP
WHERE EMP_SAL > 18000.00;
Понятно, что в соответствии с правилами SQL (и содержится строка, которая соответствует служащему с номером 2447, получающему зарплату в размере 20000 руб. Естественно, эта строка будет присутствовать в RICH_EMP. Поэтому можно было бы выполнить, например, операцию
UPDATE RICH_EMP SET EMP_SAL = EMP_SAL - 3000 WHERE EMP_NO = 4452;
Но если выполнение такой операции действительно допускается, то в результате строка, соответствующая служащему с номером 2447, исчезнет из RICH_EMP! Аналогичный эффект возникнет при выполнении операции вставки
INSERT INTO RICH_EMP (EMP_NO) 2452;
В появится строка, в которой значением столбца EMP_NO будет 2452, а значения остальных столбцов будут установлены по умолчанию. В частности, значением столбца EMP_SAL будет 10000.00. Тем самым, если подобная операция вставки действительно допустима, то мы вставили в RICH_EMP строку, которую в этой
Чтобы избежать такого противоречивого поведения представляемых таблиц, нужно включать в определение . При наличии этого раздела до реального выполнения операций модификации или вставки строк через ) условие выборки, содержащееся в выражении запросов
Вспомним теперь, что в полном виде синтаксис раздела может включать ключевые слова или . Обсудим их смысл. Предположим, что V2 определяется над V1 следующим образом:
CREATE VIEW V2 AS SELECT ... FROM V1 WHERE ... [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
Пусть над V2 выполняется некоторая операция O обновления базы данных. Тогда:
V2 определялось без раздела WITH CHECK OPTION , то при выполнении операции O будут проверяться все условия, определяющие V1 (если в определении V1 присутствовал раздел WITH CHECK OPTION ), но никаким образом не будут учитываться условия выборки, содержащееся в выражении запросов V2 ;V2 содержался раздел WITH LOCAL CHECK OPTION, то при выполнении операции O будут проверяться все условия, определяющие V1, и все условия, содержащееся в выражении запросов V2 ;V2 содержался раздел WITH CASCADED CHECK OPTION, то при выполнении операции O будут проверяться все условия, определяющие V1 (так, как если бы в определении V1 присутствовал раздел WITH CASCADED CHECK OPTION ). Тем самым, будут проверяться все V1 ; все условия всех V2.Чтобы пояснить результаты действия раздела , допустим, что в базе данных присутствуют определения двух MIDDLE_RICH_EMP и MORE_RICH_EMP:
CREATE VIEW MIDDLE_RICH_EMP AS
SELECT *
FROM EMP
WHERE EMP_SAL < 20000.00
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ];
CREATE VIEW MORE_RICH_EMP AS
SELECT *
FROM MIDDLE_RICH_EMP
WHERE EMP_SAL > 18000.00
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ];
Очевидно, что в тело (материализованного) MIDDLE_RICH_EMP будут входить следующие строки :
EMP_NO
|
DEPT_NO
|
EMP_BDATE
|
EMP_SAL
|
|---|---|---|---|
| 2440 | 1 | 1950 | 15000.00 |
| 2441 | 1 | 1950 | 16000.00 |
| 2442 | 1 | 1960 | 14000.00 |
| 2443 | 1 | 1960 | 19000.00 |
| 2444 | 2 | 1950 | 17000.00 |
| 2445 | 2 | 1950 | 16000.00 |
| 2446 | 2 | 1960 | 14000.00 |
| 2448 | 3 | 1950 | 18000.00 |
| 2449 | 3 | 1950 | 13000.00 |
В тело (материализованного) MORE_RICH_EMP будут входить следующие строки представляемой таблицы MIDDLE_RICH_EMP:
EMP_NO
|
DEPT_NO
|
EMP_BDATE
|
EMP_SAL
|
|---|---|---|---|
| 2443 | 1 | 1960 | 19000.00 |
В каждом из MIDDLE_RICH_EMP и MORE_RICH_EMP может отсутствовать или присутствовать (в одном из двух видов) раздел . В совокупности возможен один из девяти случаев:
MORE_RICH_EMP
|
none
|
|
|
|---|---|---|---|
MIDDLE_RICH_EMP
| |||
none |
Случай 1 |
Случай 2 |
Случай 3 |
|
Случай 4 |
Случай 5 |
Случай 6 |
|
Случай 7 |
Случай 8 |
Случай 9 |
Чтобы рассмотреть каждый из возможных случаев по отдельности, обсудим, что будет происходить в каждом случае при выполнении следующих двух операций модификации строк (будем называть эти операции U1 и U2 соответственно MORE_RICH_EMP, неизвестно ограничение EMP_SAL < 20000.00, на котором основывается MIDDLE_RICH_EMP .
UPDATE MORE_RICH_EMP SET EMP_SAL = EMP_SAL + 7000.00; UPDATE MORE_RICH_EMP SET EMP_SAL = EMP_SAL - 7000.00;
Случай 1. Ни в одном из .
Первый неожиданный результат состоит в том, что после выполнения операции U1 тело MORE_RICH_EMP оказывается пустым. Действительно, у единственной строки таблицы (со значением EMP_NO, равным 2443 ), одновременно удовлетворяющей условиям обоих EMP_SAL принимает значение 26000.00. После этого строка перестает удовлетворять условию MIDDLE_RICH_EMP и исчезает из результирующей таблицы MORE_RICH_EMP. Этот результат может быть особенно неожиданным для MORE_RICH_EMP имеет вид EMP_SAL > 18000.00, и соблюдение этого условия должно сохраняться при увеличении размера зарплаты.
Выполнение операции U2 также приведет к опустошению тела MORE_RICH_EMP (в не останется ни одной строки, удовлетворяющей условию этого MORE_RICH_EMP, которым известно условие MIDDLE_RICH_EMP, с удивлением обнаружат в теле результирующей таблицы новые строки.
Случай 2. В определении MIDDLE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION, а в определении MORE_RICH_EMP раздел отсутствует.
В этом случае, в соответствии с первыми двумя правилами проверки корректности выполнения операций обновления над U1 должна быть отвергнута системой (поскольку ее выполнение нарушает условие MIDDLE_RICH_EMP ). Но заметим, что такое поведение системы будет совершенно неожиданным и непонятным для тех MORE_RICH_EMP, поскольку операция U1 явно не может нарушить видимое ими ограничение.
С другой стороны, операция U2 будет успешно выполнена и по-прежнему приведет к опустошению тела результирующей таблицы MORE_RICH_EMP.
Случай 3. В определении MIDDLE_RICH_EMP содержится раздел WITH , а в определении MORE_RICH_EMP раздел отсутствует.
В этой ситуации будут проверяться условия, содержащиеся в определении MIDDLE_RICH_EMP, а также все и всех других U1 будет отвергнута системой, а операция U2 будет "успешно" выполнена. Другими словами, повторится Случай 2.
Случай 4. В определении MIDDLE_RICH_EMP раздел отсутствует, а в определении MORE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION.
Понятно, что в этом варианте операция U2 не сработает (ее выполнение не будет допущено условием "MORE_RICH_EMP ). Но операция U1 (увеличение размера зарплаты служащих) будет успешно выполнена, поскольку она не противоречит локальным ограничениям MORE_RICH_EMP.
Случай 5. В определениях MIDDLE_RICH_EMP и MORE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION.
Выполнение обеих операций U1 и U2 будет справедливо отвергнуто. На первый взгляд все в порядке. Но если над MORE_RICH_EMP будет определено еще одно V, то мы можем получить ситуацию Случая 2, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 6. В определении MIDDLE_RICH_EMP содержится раздел WITH , а в определении MORE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION.
Снова, если над MORE_RICH_EMP будет определено еще одно V, то мы можем попасть в ситуацию Случая 2, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 7. В определении MIDDLE_RICH_EMP раздел отсутствует, а в определении MORE_RICH_EMP содержится раздел WITH .
Если над MORE_RICH_EMP будет определено еще одно V, то мы можем попасть в ситуацию Случая 3, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 8. В определении MIDDLE_RICH_EMP содержится раздел WITH LOCAL CHECK OPTION, а в определении MORE_RICH_EMP - раздел WITH .
Если над MORE_RICH_EMP будет определено еще одно V, то мы можем получить ситуацию Случая 3, где V будет играть роль MORE_RICH_EMP, а MIDDLE_RICH_EMP - роль MORE_RICH_EMP.
Случай 9. В определениях MIDDLE_RICH_EMP и MORE_RICH_EMP содержится раздел WITH .
Только в этом случае операции обновления будут выполняться корректно, независимо от того, имеются ли в базе данных MORE_RICH_EMP или между MORE_RICH_EMP, MIDDLE_RICH_EMP и .
Очевидный вывод из приведенного анализа заключается в том, что единственным способом обеспечить корректность выполнения операций обновления через WITH . В этом случае поведение системы будет оставаться корректным при введении дополнительных MORE_RICH_EMP, между MORE_RICH_EMP и MIDDLE_RICH_EMP или между MIDDLE_RICH_EMP и , если в определениях всех этих WITH .
Завершим обсуждение возможностей применения операций обновления к
Во-первых, как отмечалось в лекции 3, одной из наиболее привлекательных черт
Во-вторых, на первый взгляд задача не является слишком трудной (по крайней мере, если оставаться в пределах
К сожалению, это ощущение простоты проблемы оказалось обманчивым. Было выполнено множество исследований, опубликовано множество статей (нам кажется нецелесообразным приводить список этих статей в данном курсе), но так и не удалось обнаружить полное множество алгебраических выражений, для которых возможна однозначная интерпретация операций обновления. На мой взгляд, данная ситуация оказала заметное влияние на подход к решению проблемы
В двух первых
Кстати, одна из идей, включавшихся в ранние варианты проекта SQL-3, состояла в том, чтобы расширить определение представляемой таблицы средствами, позволяющими явно специфицировать действия, которые нужно предпринимать при выполнении над , и . Другими словами, предлагалось переложить решение проблемы на плечи пользователей СУБД. Конечно, это радикальный подход, но, с другой стороны, он мог бы привести к полной анархии.
Как можно заметить, в официально принятом
Конечно, термин
В стандарте же языка SQL спецификации
Заметим, что
В языке обеспечиваются возможности определения , или , но существует и возможность определения
Можно придумать различные способы полезного применения механизма
DEPT_TOTAL_SAL таблицы DEPT хранится суммарное значение DEPT со значением столбца DEPT_NO, которое соответствует номеру отдела нового служащего.Для более подробного обсуждения
trigger_definition ::=
CREATE TRIGGER trigger_name
{ BEFORE | AFTER }
{ INSERT | DELETE | UPDATE [ OF column_commalist ] }
ON table_name [ REFERENCING
old_or_new_values_alias_list ]
triggered_action
triggered_action ::=
[ FOR EACH { ROW | STATEMENT } ]
[ WHEN left_paren conditional_expression right_paren ]
triggered_SQL_statement
triggered_SQL_statement ::= SQL_procedure_statement
| BEGIN ATOMIC
SQL_procedure_statement_semicolonlist
END
old_or_new_values_alias ::= OLD [ ROW ] [ AS ] correlation_name
| NEW [ ROW ] [ AS ] correlation_name
| OLD TABLE [ AS ] identifier
| NEW TABLE [ AS ] identifier
Естественно, в языке имеется и конструкция, отменяющая определение
.
(Конструкция в языке SQL не поддерживается.)
Как мы видим, синтаксические правила допускают несколько разновидностей определения
Если в определении , то
Выбор одного из этих ключевых слов при определении к срабатыванию или , то число возможных событий, приводящих к срабатыванию
Заметим, что в
Если в определении FOR EACH , то FOR EACH (или явная спецификация FOR EACH отсутствует), то
Включение в определение с соответствующим true. Понятно, что виды и интерпретация , различаются у FOR EACH и у FOR EACH . В первом случае условное выражение вычисляется для одной строки, которая должна быть обновлена данного
triggered_SQL_statement (будем называть ее BEGIN и END.
Недоумение читателей может вызвать неуточненная конструкция
Обсудим теперь, откуда возникает потребность в SQL_procedure_statement чаще всего используются операторы SQL обновления базы данных. Иногда (и мы покажем это на примере) для корректного определения функциональности BEGIN и END ).
Для иллюстрации случая, когда при определении (прием на работу нового служащего). Если значение столбца DEPT_NO в очередной вставляемой строке отлично от NULL, то DEPT_EMP_NO и DEPT_TOTAL_SAL строки таблицы DEPT со значением столбца DEPT_NO, которое соответствует номеру отдела нового служащего (пример 17.10):
CREATE TRIGGER DEPT_CORRECTION AFTER INSERT ON EMP
FOR EACH ROW
WHEN (EMP.DEPT_NO IS NOT NULL)
UPDATE DEPT SET
DEPT_EMP_NO = DEPT_EMP_NO + 1,
DEPT_TOTAL_SAL = DEPT_TOTAL_SAL + EMP_SAL
WHERE DEPT.DEPT_NO = EMP.DEPT_NO;
Теперь предположим, что при увольнении служащего (удалении строки из таблицы
EMP_NO : EMP_NO |
EMP_NAME : VARCHAR |
DEPT_NO : DEPT_NO |
Определение соответствующего
CREATE TRIGGER EMP_DISMISSION AFTER DELETE ON EMP
FOR EACH ROW
BEGIN ATOMIC
INSERT INTO EMP_DISMISSED
ROW (EMP.EMP_NO, EMP.EMP_NAME, EMP.DEPT_NO);
UPDATE DEPT SET
DEPT_EMP_NO = DEPT_EMP_NO - 1,
DEPT_TOTAL_SAL = DEPT_TOTAL_SAL - EMP_SAL
WHERE DEPT.DEPT_NO = EMP.DEPT_NO
END;
При
Обсудим понятие должно поддерживаться правило, в соответствии с которым каждый служащий, становящийся CHANGE_MNG_NO следующим образом:
CREATE TRIGGER CHANGE_MNG_NO AFTER UPDATE OF PRO_MNG ON PRO
FOR EACH ROW
UPDATE EMP SET EMP_SAL = EMP_SAL + 10000.00
WHERE EMP_NO = PRO_MNG;
Но очевидно, что для поддержания корректности данных в таблице DEPT нам требуется EMP_SAL в таблице . Определим соответствующий DEPT_CORRECTION_1:
CREATE TRIGGER DEPT_CORRECTION_1
AFTER UPDATE OF EMP_SAL ON EMP
REFERENCING OLD ROW AS OLD_EMP NEW ROW AS NEW_EMP
FOR EACH ROW
UPDATE DEPT SET
DEPT_TOTAL_SAL =
DEPT_TOTAL_SAL + NEW_EMP.EMP_SAL -
OLD_EMP.EMP_SAL
WHERE EMP.DEPT_NO = DEPT.DEPT_NO;
Пусть теперь выполняется операция
UPDATE PRO SET PRO_MNG = 4455 WHERE PRO_NO = 554;
Сразу после выполнения этой операции сработает CHANGE_MNG_NO. Этот CMN. Заметим, что исходный оператор модификации в действительности изменяет только одну строку таблицы , но CHANGE_MNG_NO это неизвестно, и он будет работать так, как если бы изменялось произвольное число строк таблицы .
Выполнение операции модификации таблицы приведет к срабатыванию DEPT_CORRECTION_1. В этот момент CMN будет "упрятан в стек", образуется и станет активным DR1. После завершения DR1 больше не требуется, и он ликвидируется, а из стека восстанавливается CMN, в котором и будет завершено CHANGE_MNG_NO.
INSERT , UPDATE или DELETE ; UPDATE ); STATEMENT , уже ROW , уже Отслеживание уже
При создании
Мы уже продемонстрировали использование старых и новых значений в определении DEPT_CORRECTION_1. Поскольку эта возможность является важной особенностью языка SQL, обсудим ее более подробно.
Сначала немного поговорим о синтаксисе. Итак, в определении REFERENCING old_or_new_values_alias_list, причем список определений псевдонимов может включать следующие элементы:
OLD [ ROW ] [ AS ] correlation_name NEW [ ROW ] [ AS ] correlation_name OLD TABLE [ AS ] identifier NEW TABLE [ AS ] identifier
Каждая из этих конструкций может входить в список определений псевдонимов не более одного раза, и спецификации OLD и NEW могут присутствовать только в определении . Определяемые корреляционные имена и псевдонимы можно использовать внутри NEW ) или NEW TABLE ), то эти имена можно использовать для ссылок на значения, которые будут существовать в или . Если же определяется корреляционное имя для старых значений ( OLD ) или OLD TABLE ), то данные имена можно использовать для ссылок на значения, которые существовали в или . Конечно, нельзя использовать NEW или NEW TABLE в , поскольку никакие новые значения не создаются. Аналогично, нельзя использовать OLD или OLD TABLE в , поскольку никакие старые значения не существовали.
можно использовать корреляционное имя, определенное в конструкции OLD , для ссылки на значения строки, удаляемой или OLD TABLE, для ссылки на любое значение NEW и NEW TABLE.
Для имеется существенное ограничение: в них не разрешается использовать конструкции OLD TABLE и NEW TABLE, а внутритриггерный SQL-оператор не может производить какие-либо изменения в базе данных. Основанием для такого ограничения является то, что на OLD TABLE и NEW TABLE, могут существенно влиять
В SQL:1999 не запрещается определение нескольких или ) и срабатывающих по одному и тому же событию. Понятно, что при возникновении условия срабатывания всех таких
Решение, принятое в SQL, является предельно простым, хотя и несколько странным. При определении каждого CREATE , и все или ) и срабатывающие по одному и тому же событию, упорядочиваются в соответствии со своими временными метками. Тогда при возникновении условия срабатывания всех
Подход к установлению
И еще одно интересное свойство
В разделе "Введение" лекции 12 мы достаточно подробно обсуждали механизм определения
Конечно,
Однако даже в тех СУБД, где не смешиваются механизмы . Если выполняется некоторая операция обновления таблицы T, то после ее выполнения и срабатывания всех T и видом произведенной операции, а также соответствующие
В заключение этого раздела, посвященного механизму
В этой лекции мы обсудили важные аспекты языка SQL, относящиеся к механизмам обновления данных. В первом разделе были рассмотрены операторы прямого SQL, предназначенные для вставки, модификации и удаления данных из существующих таблиц. Операторы и этой категории иногда называют поисковыми, поскольку в них включаются условия на строки таблицы, которые должны быть модифицированы или удалены. В языке SQL определены так-же позиционные операторы модификации и удаления строк, а также динамические позиционные варианты данных операторов, но для их обсуждения требуется общее рассмотрение встраиваемого и динамического SQL, что выходит за рамки данного курса. На мой взгляд, поисковые версии операторов модификации и удаления хорошо характеризуют соответствующие возможности языка SQL. Кроме того, оператор , представленный в этой лекции, специфицирован в языке SQL только в таком варианте.
Второй раздел лекции посвящен обсуждению возможностей языка SQL, связанных с
Наконец, в третьем разделе лекции рассматривался механизм
Один из основных выводов лекции состоит в том, что в
Часть следующей лекции, относящаяся к средствам языка SQL, которые предназначены для управления транзакциями, также имеет непосредственное отношение к операторам обновления баз данных.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.