Практическое занятие № 10
Тема: "Работа с триггерами в разных СУБД"
Цель работы: получить практические навыки по созданию триггеров для таблиц в разных СУБД
Ход работы
Работа в SQL Server
Пусть имеется БД "dbase" в формате SQL Server. Данная БД состоит из 6 таблиц со следующей структурой:

Таблицы связаны так:
| Главная таблица | Подчиненная таблица | Поле для связи | Тип связи |
| otdelen | spec | id_otd | 1 : ∞ |
| spec | grupy | id_spec | 1 : ∞ |
| grupy | students | id_grup | 1 : ∞ |
| students | ocenki | id_stud | 1 : ∞ |
| predmety | ocenki | id_predmet | 1 : ∞ |
Выполните подключение БД к серверу (если она отсутствует).
Указания: разархивируйте архив.
Запустите утилиту "Microsoft SQL Server Management Studio", пройдите регистрацию введя информацию: Параметры подлинности = "Проверка подлинности SQL Server", Имя пользователя=sa, пароль=111 (у Вас может быть свой пароль).
В дереве объектов вызовите контекстное меню папки "Базы данных" и выберите команду "Присоединить". В правой части появится окно, в котором с помощью кнопки "Добавить" укажите файл из архива и щелкните ОК.
В результате у вас на сервере будет зарегистрирована новая БД.
Для создания запроса выберите в левой части нужную БД и щелкните на кнопке
"Создать запрос"
В правой части окна
введите текст запроса.
Для выполнения запроса щелкните на кнопке "Выполнить"
.
В нижней части окна отобразится набор отобранных данных.
На основании информации из БД создайте несколько триггеров для решения поставленных задач.
1. Для таблицы ocenki создать механизм логирования изменений. При этом нужно сохранять id_ocenki, старую оценку, новую оценку, имя пользователя, дату и время изменения, тип операции (добавление, удаление, редактирование).
2. Для таблицы students создать триггер, который при добавлении, удалении или изменении студентов, автоматически подсчитывает количество студентов в каждой группе.
3. Для таблицы ocenki создайте триггер, который в отдельном поле переводит оценку из 5-бальной системы в 100-бальную по формуле оценка * 20.
Указания:
Для создания триггера в левой части окна утилиты откройте узел нужной таблицы БД, в контекстном меню папки Триггеры выберите команду "Создать триггер". В результате откроется окно с шаблоном кода для ввода текста триггера. Вместо предлагаемого шаблона введите свой набор команд.
Задание 1.
Для создания журнала логирования изменений оценок создадим отдельную таблицу с именем OcenkiLog и следующей структурой:

Для решения задачи, операции добавления и обновления оценки поместим в отдельный триггер, который создадим для таблицы ocenki
create trigger saveinsupdocenka
-- имя таблицы, для которой создается триггер
on ocenki
-- события срабатывания триггера
-- в нашем случае после добавления или изменения оценки
after insert, update
as
begin
-- код триггера
-- если изменения произошли в поле ocenka
if update(ocenka)
begin
set nocount on;
-- описываем переменные
-- идентификатор новой оценки
declare @idocenkanew int;
-- идентификатор старой (до изменения) оценки
declare @idocenkaold int;
-- новая оценка после изменения или добавления
declare @ocenkanew decimal(3,0);
-- старая оценка до изменения
declare @ocenkaold decimal(3,0);
-- с помощью запросов получаем значения для наших переменных
-- вначале считываем значения из новой записи таблицы inserted
select @idocenkanew = (select id_ocenka from inserted);
select @ocenkanew = (select ocenka from inserted);
-- затем считываем значения из старой записи таблицы deleted
select @idocenkaold = (select id_ocenka from deleted);
select @ocenkaold = (select ocenka from deleted);
-- в таблицу OcenkiLog добавляем новую запись
-- и заполняем все поля значениями переменных
-- имя пользователя получаем встроенной функцией user_name()
-- дату и время получаем встроенной функцией getdate()
-- если старая оценка существует (значит оценка изменена)
if (@ocenkaold is not null)
-- добавляем в лог запись с отметкой 'update'
insert into ocenkilog
values(@idocenkanew, @ocenkaold, @ocenkanew, user_name(), getdate(), 'update')
-- иначе, если старая оценка не существует (значит оценка добавлена)
else if (@ocenkaold is null)
-- добавляем в лог запись с отметкой 'insert'
insert into ocenkilog
values (@idocenkanew, null, @ocenkanew, user_name(), getdate(), 'insert');
end;
end;
Операцию удаления оценки оценки поместим в отдельный триггер, который также создадим для таблицы ocenki.
create trigger savedelocenka
-- имя таблицы, для которой создается триггер
on ocenki
-- событие срабатывания триггера
-- в нашем случае после удаления оценки
after delete
as
begin
-- код триггера
set nocount on;
-- описываем переменные
-- идентификатор старой (удаленной) оценки
declare @idocenkaold int;
-- старая (удаленная) оценка
declare @ocenkaold decimal(3,0);
-- с помощью запросов получаем значения для наших переменных
-- считываем значения из старой (удаленной) записи таблицы deleted
select @idocenkaold = (select id_ocenka from deleted);
select @ocenkaold = (select ocenka from deleted);
-- в таблицу OcenkiLog добавляем новую запись
-- и заполняем все поля значениями переменных
-- имя пользователя получаем встроенной функцией user_name()
-- дату и время получаем встроенной функцией getdate()
-- ставим отметку операции 'delete'
insert into OcenkiLog
values (@idocenkaold, @ocenkaold, null, user_name(), getdate(), 'delete');
end;
После создания триггеров попробуйте изменить или добавить оценку в таблице ocenki и проверьте, что в таблицу OcenkiLog добавляются записи обо всех внесенных изменениях.
Задание 2.
Для хранения количества студентов в группе добавим в таблицу grupy поле kolstud как показано на рисунке:

Для таблицы students создадим триггер с параметрами AFTER UPDATE, INSERT, DELETE вида:
create trigger calckolstud
-- для таблицы students
on students
-- события срабатывания триггера
-- в нашем случае после добавления, удаления или обновления студента
after insert,delete,update
as
begin
set nocount on;
-- код триггера
-- описываем переменную
-- переменная для получения номера группы удаленного студента
declare @old int;
-- переменная для получения номера группы нового студента
declare @new int;
-- работаем с новым или перемещенным студентом
-- если у студента обновилось поле id_grup (его добавили или переместили)
if update(id_grup)
-- получаем значение id_grup нового студента
select @new = (select top 1 id_grup from inserted);
-- работаем с удаленным студентом
--получаем значение id_grup удаленного студента
select @old = (select top 1 id_grup from deleted);
--если @old существует, то есть имеется удаленная запись студента
if (@old is not null)
-- в подзапросе считаем количество студентов в группе, где учился удаленный студент
-- обновляем поле kolstud в таблице grupy
-- для группы, где учился удаленный студент
update grupy
set kolstud = (select count(*) from students where id_grup = @old)
where id_grup = @old;
-- если new существует, то есть добавлена или изменена запись студента
if (@new is not null)
-- обновляем поле kolstud в таблице grupy
-- для группы, куда добавлен или перемещен новый студент
update grupy
set kolstud = (select count(*) from students where id_grup = @new)
where id_grup = @new;
end;
Попробуйте изменить значение поля id_grup любого студента в таблице students и убедитесь, что в таблице grupy автоматически обновляется значение в поле kolstud.
Попробуйте добавить нового студента в таблицу students и убедитесь, что в таблице grupy автоматически обновляется значение в поле kolstud для соответствующей группы.
Попробуйте удалить студента из таблицы students и убедитесь, что в таблице grupy автоматически обновляется значение в поле kolstud для соответствующей группы.
Задание 3.
Данную задачу в SQL Server можно решить без триггеров. Для этого достаточно в структуре таблицы ocenki создать вычисляемое поле с формулой:
ocenka*20
Тем не менее покажем решение этой же задачи с помощью триггеров. Для хранения оценки в 100-бальном виде добавим в таблицу ocenki поле ocenka100 как показано на рисунке:

Для таблицы ocenki создадим триггер с параметрами AFTER UPDATE, INSERT вида:
create trigger convert100
-- для таблицы ocenki
on ocenki
-- события срабатывания триггера
-- в нашем случае после добавления или обновления оценки
after insert, update
as
begin
set nocount on;
-- код триггера
-- если изменения произошли в поле ocenka
if update(ocenka)
begin
set nocount on;
-- описываем переменные
-- идентификатор новой оценки
declare @idocenkanew int;
-- новая оценка после изменения или добавления
declare @ocenkanew decimal(3,0);
-- с помощью запросов получаем значения для наших переменных
-- определяем идентификатор измененной или добавленной оценки
select @idocenkanew = (select id_ocenka from inserted);
-- определяем значение измененной или добавленной оценки
select @ocenkanew = (select ocenka from inserted);
-- обновляем таблицу ocenki
-- расссчитsdаем оценку по 100-бальной шкале
-- при этом изменения применяются только к оценке с найденным идентификатором
update ocenki
set ocenka100 = @ocenkanew*20
where id_ocenka=@idocenkanew;
end;
end;
Попробуйте в таблице ocenki изменить или добавить новую оценку и убедитесь, что поле ocenka100 рассчитывается автоматически.
Работа в MySQL
Скачайте исходную БД в формате MySQL. Выполните все рассмотренные выше запросы в этой СУБД.
Указания: распакуйте архив. В архиве находится файл со скриптом БД.
Запустите утилиту EMS SQL Manager for MySQL. В правой части окна программы выберите команду "Выполнить SQL скрипт". В новом окне выберите команду "Выполнить скрипт из файла". В диалоговом окне укажите распакованный файл скрипта. Если появится окно регистрации, то укажите Пользовать=root, Пароль=111. Если такого окна не появилось, то нажимайте в окне ОК. Появится сообщение, что скрипт выполнен успешно и появится окно для регистрации БД. Перенесите ее в правую часть окна и нажмите ОК. В результате БД будет установлена, зарегистрирована и готова к работе.
В левой части окна можете открыть БД, просмотреть ее таблицы.
Для создания триггера можно в левой части окна утилиты открыть узел нужной БД. В результате отобразится список объектов, среди которых будет узел "Триггеры".
Для создания триггера в контекстном меню папки "Триггеры" выберите команду "Новый объект: триггер...". В результате в правой части откроется окно для ввода параметров триггера.
В верхней части введите имя триггера, укажите таблицу, для которой создается триггер. С помощью переключателей укажите тип события (BEFORE или AFTER) и само событие (INSERT, UPDATE, DELETE).
Внизу между операторными скобками BEGIN...END введите текст триггера.
После ввода текста триггера щелкните на команде "Compile". Если ошибок нет, то появится сообщение об успешном выполнении команды. Обновите папку Триггеры клавишей F5, чтобы увидеть созданный триггер.
Задание 1.
Для создания журнала логирования изменений оценок создадим отдельную таблицу с именем OcenkiLog и следующей структурой:

Так как в MySQL нельзя создавать триггеры на несколько событий одновременно, то для решения задачи каждую операцию (добавление, изменение, удаление) поместим в отдельный триггер.
Триггер на добавление новой оценки имеет следующие параметры:

После задания всех параметров щелкните на команде "Compile".
Триггер на изменение оценки имеет следующие параметры:

После задания всех параметров щелкните на команде "Compile".
Триггер на удаление оценки имеет следующие параметры:

После задания всех параметров щелкните на команде "Compile".
После создания триггеров попробуйте изменить или добавить оценку в таблице ocenki и проверьте, что в таблицу OcenkiLog добавляются записи обо всех внесенных изменениях.
Задание 2.
Для хранения количества студентов в группе добавим в таблицу grupy поле kolstud как показано на рисунке:
Так как в MySQL нельзя создавать триггеры на несколько
событий одновременно, то для решения задачи каждую операцию (добавление,
изменение, удаление) поместим в отдельный триггер.
Триггер на добавление нового студента имеет
следующие параметры:

После задания всех параметров щелкните на команде "Compile".
Триггер на изменение студента имеет следующие параметры:

После задания всех параметров щелкните на команде "Compile".
Триггер на удаление студента имеет следующие параметры:

После задания всех параметров щелкните на команде "Compile".
Попробуйте изменить значение поля id_grup любого студента в таблице students и убедитесь, что в таблице grupy автоматически обновляется значение в поле kolstud.
Попробуйте добавить нового студента в таблицу students и убедитесь, что в таблице grupy автоматически обновляется значение в поле kolstud для соответствующей группы.
Попробуйте удалить студента из таблицы students и убедитесь, что в таблице grupy автоматически обновляется значение в поле kolstud для соответствующей группы.
Задание 3.
В СУБД MySQL нет возможности создавать в таблицах вычисляемые поля, поэтому, в отличии от SQLServer, данную задачу можно решить только с помощью триггеров.
При этом расчет значения вычисляемого поля должно выполняться ДО ВСТАВКИ или ДО ИЗМЕНЕНИЯ записи в таблице, то есть в событиях Before Insert или Before Update.
Так как в MySQL нельзя создавать триггеры на несколько событий одновременно, то для решения задачи каждую операцию (добавление, изменение, удаление) поместим в отдельный триггер.
Для хранения оценки в 100-бальном виде добавим в таблицу ocenki поле ocenka100 как показано на рисунке:

Триггер на добавление новой оценки.

После задания всех параметров щелкните на команде "Compile".
Триггер на изменение оценки.

После задания всех параметров щелкните на команде "Compile".
Попробуйте в таблице ocenki изменить или добавить новую оценку и убедитесь, что поле ocenka100 рассчитывается автоматически (при внесении изменений в таблицу нажимайте на кнопку "Обновить данные" для просмотра изменений).