- •Раздел 2.7 Использование uml-нотации для разработки баз данных
- •Тема 2.7.1 Основные понятия баз данных. Ключи, триггеры и хранимые процедуры Лекция № 23 (2часа)
- •Содержание
- •Домашнее задание
- •Контрольные вопросы
- •Лекция № 24 (2часа)
- •“Реляционные, древовидные и объектно-ориентированные базы данных” Артур б. Смит m. Computing May/June 1996, V.4 n.2
- •“Проектирование реляционных баз данных. Просто и доступно” Джен л.Харрингтон – издательство “Лори”, 2000.-230 с. Содержание
- •Контрольные вопросы
- •Тема 2.7.2 Организация реляционной бд. Разновидности баз данных Лекция № 25 (2часа)
- •“Реляционные, древовидные и объектно-ориентированные базы данных” Артур б. Смит m. Computing May/June 1996, V.4 n.2
- •“Проектирование реляционных баз данных. Просто и доступно” Джен л.Харрингтон – издательство “Лори”, 2000.-230 с. Содержание
- •1. Тип данных
- •3. Схема отношения, схема базы данных
- •Домашнее задание
- •4. Кортеж, отношение
- •Структура реляционной модели данных
- •Домашнее задание
- •Контрольные вопросы
- •Лекция № 26 (2часа)
- •“Реляционные, древовидные и объектно-ориентированные базы данных” Артур б. Смит m. Computing May/June 1996, V.4 n.2
- •“Проектирование реляционных баз данных. Просто и доступно” Джен л.Харрингтон – издательство “Лори”, 2000.-230 с. Содержание Целостность реляционных данных
- •Домашнее задание
- •Контрольные вопросы
- •Тема 2.7.3 Расширение uml для моделирования базы данных Лекция № 27 (2часа)
- •Содержание
- •Домашнее задание
- •Контрольные вопросы
- •Тема 2.7.4. Особенности отображения свойств объектов и классов при моделировании баз данных. Моделирование бд. Лекция № 28 (2часа)
- •Содержание
- •Домашнее задание
- •Контрольные вопросы
- •Лекция № 29 (2часа)
- •Содержание
- •Домашнее задание
- •Контрольные вопросы
- •Лекция № 30 (2часа)
- •Содержание
- •Домашнее задание
- •Контрольные вопросы
Домашнее задание
1. Ознакомится с теоретическими сведениями лекции №23.
2. Ответить на контрольные вопросы.
Контрольные вопросы
Определение БД.
Определение СУБД.
Что такое ключ в терминологии БД.
Внешний ключ.
Простой ключ.
Составной ключ.
Первичный ключ.
Определение генератора.
Синтаксис представления генератора.
Определение триггера.
Синтаксис представления триггера.
Лекция № 24 (2часа)
Тема: Хранимые процедуры. Использование генераторов в триггерах и хранимых процедурах.
Цель: Ознакомится с понятием хранимой процедуры. Рассмотреть синтаксис написания хранимой процедуры с помощью языка запросов SQL.
Литература:
“Реляционные, древовидные и объектно-ориентированные базы данных” Артур б. Смит m. Computing May/June 1996, V.4 n.2
“Проектирование реляционных баз данных. Просто и доступно” Джен л.Харрингтон – издательство “Лори”, 2000.-230 с. Содержание
Хранимая процедура
Хранимая процедура — объект базы данных, представляющий собой набор SQL-инструкций, который компилируется один раз и хранится на сервере. Хранимые процедуры очень похожи на обыкновенные процедуры языков высокого уровня, у них могут быть входные и выходные параметры и локальные переменные, в них могут производиться числовые вычисления и операции над символьными данными, результаты которых могут присваиваться переменным и параметрам. В хранимых процедурах могут выполняться стандартные операции с базами данных (как DDL, так и DML). Кроме того, в хранимых процедурах возможны циклы и ветвления, то есть в них могут использоваться инструкции управления процессом исполнения.
Сохраняемые процедуры похожи на определяемые пользователем функции (UDF). Основное различие заключается в том, что пользовательские функции можно использовать как и любое другое выражение в SQL запросе, в то время как сохраняемые процедуры должны быть вызваны с помощью функции CALL:
CALL процедура(...)
или
EXECUTE процедура(...)
Сохраняемые процедуры могут возвращать множества результатов, т.е. результаты запроса SELECT. Такие множества результатов могут обрабатываться, используя курсоры, другими сохраненными процедурами, возвращая указатель результирующего множества, либо же приложениями. Сохраняемые процедуры могут также содержать объявленные переменные для обработки данных и курсоров, которые позволяют организовать цикл по нескольким строкам в таблице. Стандарт SQL предоставляет для работы выражения IF, LOOP, REPEAT, CASE и многие другие. Сохраняемые процедуры могут принимать переменные, возвращать результаты или изменять переменные и возвращать их, в зависимости от того, где переменная объявлена.
Реализация хранимых процедур варьируется от одной СУБД к другой. Большинство крупных поставщиков баз данных поддерживают их в той или иной форме. В зависимости от СУБД, хранимые процедуры могут быть реализованы на различных языках программирования, таких, как SQL, Java, C или C++. Сохраняемые процедуры, написанные не на SQL, могут самостоятельно выполнять SQL-запросы, а могут и не выполнять. Все более широкое использование сохраняемых процедур привело к появлению процедурных элементов в языке SQL стандарта SQL:1999 и SQL: 2003 в части SQL/PSM. Это сделало SQL императивным языком программирования. Большинство СУБД предлагают собственные расширения производителя, сверх SQL.
CREATE PROCEDURE T_SPECIALNOST_INSERT (ID_SPEC INTEGER,SPEC_NAME VARCHAR(30),PAY SMALLINT)
AS BEGIN
INSERT INTO T_SPECIALNOST(ID_SPEC,SPEC_NAME,PAY)
VALUES(:ID_SPEC,:SPEC_NAME,:PAY);
END*
Использование генераторов в триггерах и хранимых процедурах
Пример триггера, автоматически присваивающего уникальное значение ключевому полю таблицы:
создадим генератор для уникальной идентификации клиентов:
CREATE GENERATOR NEWCLIENT;
создадим триггер для таблицы CLIENTS :
CREATE TRIGGER TBI_CLIENTS FOR CLIENTS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
NEW.CLIENT_ID = GEN_ID(NEWCLIENT, 1);
END
В результате при создании новой записи полю CLIENT_ID будет автоматически присваиваться новое значение.
Однако при использовании генератора в триггере возникает проблема на клиентской стороне (например в BDE, используемом в Delphi, C++Builder ...), когда клиентское приложение пытается перечитать только-что вставленную запись. Поскольку триггер меняет значение первичного ключа вставляемой записи, BDE "теряет" такую запись и чаще всего выдает сообщение "Record/Key deleted". Поскольку SQL-сервер не может сообщить клиентскому приложению о новом значении ключевого поля, необходимо сначала запросить уникальное значение с сервера, и только затем использовать его во вставляемой записи. Сделать это можно при помощи хранимой процедуры
CREATE PROCEDURE GETNEWCLIENT
RETURNS (NID INTEGER)
AS
BEGIN
NID = GEN_ID(NEWCLIENT, 1);
END
В Delphi, можем поместить компонент TStoredProc на форму, подсоединить его к данной процедуре, и например в методе таблицы BeforePost написать следующее
begin
if DataSource.State = dsInsert then
begin
StoredProc1.ExecProc;
ClientTable.FieldByName('CLIENT_ID').asInteger:=
StoredProc1.Params[0].asInteger;
end;
end;
После этого вышеприведенный триггер TBI_CLIENTS можно либо удалить, либо переписать так, чтобы генератор использовался только когда поле первичного ключа случайно приобрело значение NULL (например когда к таблице CLIENTS доступ осуществляется не через ваше приложение):
ALTER TRIGGER TBI_CLIENTS
AS
BEGIN
IF (NEW.CLIENT_ID IS NULL) THEN
NEW.CLIENT_ID = GEN_ID(NEWCLIENT, 1);
END
Однако использование хранимой процедуры не всегда удобно - BDE может решить, что процедура вероятно изменяет какие-то данные на сервере, и в режиме autocommit завершит текущую транзакцию, что вызовет прочитывание данных TTable и TQuery. Более простым способом является получение значения генератора при помощи запроса:
SELECT GEN_ID(NEWCLIENT, 1) FROM RDB$DATABASE
При этом, если запрос помещен например в Query2, текст в BeforePost будет следующим:
begin
if DataSource.State = dsInsert then
begin
Query2.Open;
ClientTable.FieldByName('CLIENT_ID').asInteger:=
Query2.Fields[0].asInteger;
Query2.Close;
end;
end;
Такой способ более предпочтителен, чем использование хранимой процедуры для получения значения генератора, особенно при большом количестве генераторов.
Изменение значения генератора
Значение генератора можно переустановить при помощи оператора DDL
SET GENERATOR generatorname TO value;
Однако не сможем использовать такое выражение в теле триггера или хранимой процедуры, т.к. там можно использовать только операторы DML (а не DDL).
Если мы хотим обнулить генератор, или присвоить ему определенное значение в теле хранимой процедуры, то можно это сделать, используя функцию GEN_ID:
(В данном примере генератор NEWCLIENT увеличивается на свое-же значение с отрицательным знаком.)
...
TEMPVAR = GEN_ID(NEWCLIENT, -GEN_ID(NEWCLIENT, 0);
...
Приложения, процедуры и триггеры, которые в данный момент используют этот генератор, могут предполагать что он не будет "обнулен". Обязательно нужно проверять "обнуление" генератора на возникновение конфликтных ситуаций при работе 2-х и более пользователей.
Получение текущего значения генераторов
Текущее значение генератора можно получить, вызвав функцию GEN_ID с нулевым увеличением значения генератора. Это можно сделать не только в триггере или хранимой процедуре, но и оператором SELECT
SELECT GEN_ID(NEWCLIENT, 0) FROM RDB$DATABASE
Результатом выполнения запроса будет одна запись с одним полем, содержащим текущее значение генератора. Таблица RDB$DATABASES выбрана как содержащая в большинстве случаев одну запись, хотя использовать можно и любую другую таблицу.
При работе в многопользовательских средах нужно быть внимательным - в то время как получили "текущее" значение генератора, другое приложение может его изменить, и таким образом "текущее" значение окажется устаревшим. Тем более не рекомендуется использовать "текущее" значение генератора для его последующего изменения.
Удаление генераторов
В языке DDL Borland Interbase нет оператора для удаления генератора. Запись о генераторе создается в таблице RDB$GENERATORS. Эту запись, безусловно, можно удалить. Однако место, распределенное на странице генераторов, освобождено не будет. Оно будет освобождено только после того, как сделаем текущей БД BACKUP/RESTORE.
