Вы находитесь на странице: 1из 8

Министерство образования, культуры и исследований Республики

Молдова
Технический университет Молдовы
Департамент программной инженерии и автоматики

Отчет
по лабораторной работе №10
Тема: Пользовательские функции. Хранимые процедуры. Триггеры.

Выполнил: Студент группы TI-186 Лях Аркадий


Проверил: Преподаватель Саранчук Дориан

Кишинев 2020
Цели работы:
1. Научиться создавать и использовать пользовательские функции в SQL
Server.
2. Научиться создавать и использовать хранимые процедуры в SQL Server.
3. Научиться создавать и использовать триггеры в SQL Server.
Задания к лабораторной работе:
Задание 1. Создание пользовательских функций
1. Создайте пользовательскую функцию, которая возвращает среднее
количество участников в команде,если id проекта больше либо равно,
указанному в аргументе функции. Запустите её.
Измените эту функцию. Проверьте её работу.
--Вычислить среднее количество участников во всех проектах, если id проекта больше
либо равно, указанному в аргументе функции
CREATE FUNCTION dbo.Среднее_количество (@ID_проекта int)
RETURNS int
AS
BEGIN
DECLARE @tmp int;
SELECT @tmp = AVG(Количество_участников)
FROM Виды_проекта
WHERE ID_вида_проекта<=@ID_проекта
IF (@tmp IS NULL)
SET @tmp = 0
RETURN @tmp
END
GO

SELECT dbo.Среднее_количество(10) as Среднее

SELECT dbo.Среднее_количество(10) as Среднее


DROP FUNCTION dbo.Среднее_количество
--Вычислить среднее количество участников во всех проектах,но уже без учета id проекта
ALTER FUNCTION dbo.Среднее_количество ()
RETURNS int
AS
BEGIN
DECLARE @tmp int;
SELECT @tmp = AVG(Количество_участников)
FROM Виды_проекта
IF (@tmp IS NULL)
SET @tmp = 0
RETURN @tmp
END
GO
SELECT dbo.Среднее_количество() as Среднее
2. Создайте пользовательскую функцию, которая возвращает данные в
виде таблицы. Проверьте работу функции.
--Функция,которая по id(указанному в аргументе функции) проекта возвращает информацию
о его директоре,виде проекта и названии.
CREATE FUNCTION dbo.Проекта(@ID int)
RETURNS @tmpInformation TABLE
(
ID_проекта int not null primary key,
ID_директора int not null ,
Название_проекта nvarchar (50) not null,
ID_вида_проекта int not null unique)
AS BEGIN
DECLARE
@ID_проекта int,
@ID_директора int,
@Название_проекта nvarchar (50),
@ID_вида_проекта int;
SELECT
@ID_проекта=ID_проекта,
@ID_директора=ID_директора,
@Название_проекта=Название_проекта,
@ID_вида_проекта=ID_вида_проекта
FROM Проект
WHERE ID_проекта=@ID
IF @ID IS NOT NULL
BEGIN
INSERT @tmpInformation
SELECT @ID_проекта,@ID_вида_проекта,@Название_проекта,@ID_директора;
END
RETURN
END

SELECT * FROM dbo.Проекта (9)

Задание 2. Создание хранимой процедуры


Создайте хранимую процедуру.Запустите её. Измените процедуру так,
чтобы она восстановила старые значения, затронутых предыдущим
вызовом процедуры. Запустите её.
--Хранимая процедура,которая записывает в новую таблицу TEST текущее число и общее
количество сотрудников
drop procedure dbo.ID
create procedure dbo.ID
@dopID[int]=0 OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET @dopID=0;
BEGIN TRY
INSERT INTO dbo.TEST (Дата,Количество_сотрудников)
VALUES (GETDATE(),(SELECT COUNT(ID_сотрудника) AS Количество_сотрудников FROM
Персонал))
SET @dopID = @@IDENTITY;
END TRY
BEGIN CATCH
PRINT 'Ошибка в хранимой процедуре dbo.ID';
RETURN -1;
END CATCH
END;

EXECUTE dbo.ID
SELECT * FROM dbo.TEST

Задание 3. Работа с триггерами


1.Создайте DML триггер, который при добавлении нового кортежа в
отношение автоматически выводит некоторую информацию.
--При добавлении нового кортежа в отношение «Персонал» автоматически выводит некоторую
информацию о сотруднике, а также дату записи.
CREATE TRIGGER Добавление_кортежей
ON Персонал
AFTER INSERT
AS
DECLARE @now DATETIME
SET @now = getdate()
BEGIN TRY
SELECT 'INSERTED ROW', @now,
inserted.Имя_сотрудника,inserted.Фамилия_сотрудника,inserted.Дата_рождения,inserted.ID
_сотрудника
FROM INSERTED
END TRY
BEGIN CATCH
PRINT 'Error!'
ROLLBACK TRANSACTION
END CATCH

2. Напишите DML триггер, который обеспечил бы правильное


(последовательное) заполнение кортежами двух заданных связанных
отношений и позволил бы избежать ошибок на уровне внешних ключей.
CREATE TRIGGER Заполнение_кортежами
ON Участники_Проекта
INSTEAD OF INSERT
AS
DECLARE @now DATETIME
SET @now = getdate()
BEGIN TRY
IF NOT EXISTS (SELECT ID_проекта
FROM Проекта WHERE ID_проекта = (SELECT ID_проекта FROM inserted))
PRINT N'Проекта с таким ID не существует, пожалуйста добавьте данную команду в базу!'
ELSE IF NOT EXISTS (SELECT ID_сотрудника
FROM Персонал WHERE ID_сотрудника = (SELECT ID_сотрудника FROM inserted))
PRINT N'Сотрудника с таким ID не существует, пожалуйста добавьте данного сотрудника в
базу!'
ELSE SELECT 'INSERTED ROW', @now, inserted.ID_проекта, inserted.ID_сотрудника
FROM INSERTED
END TRY
BEGIN CATCH
PRINT 'Error!'
ROLLBACK TRANSACTION
END CATCH

insert into Участники_Проекта (ID_сотрудника,ID_проекта)


values (30,2)
insert into Участники_Проекта (ID_сотрудника,ID_проекта)
values (9,30)

3. Напишите DML триггер, который реализует комплексное


многотабличное ограничение к базе данных и следит за соблюдением
данного ограничения для каждого введенного, измененного, или
удаленного кортежа.
CREATE TRIGGER Многотабличное_ограничение
ON Проекта
FOR INSERT,UPDATE,DELETE
AS
DECLARE @now DATETIME
SET @now = getdate()
BEGIN TRY
IF EXISTS (SELECT Дата_рождения FROM Персонал WHERE Дата_рождения > (SELECT
Дата_формирования FROM inserted))
PRINT N'Дата_формирования указана неверно!'
ELSE SELECT 'INSERTED ROW', @now, inserted.ID_вида_проекта
FROM INSERTED
ROLLBACK TRANSACTION
END TRY
BEGIN CATCH
PRINT 'Error!'
ROLLBACK TRANSACTION
END CATCH
UPDATE Проекта SET Дата_формирования = '1918-09-02' WHERE ID_проекта=3

4. Создайте копию отношения «Директора» и назовите его


«Директора_Тест». Затем создайте DDL триггер, который при попытке
удалить отношение «Директора_Тест» вместо того чтобы его удалить,
заменяет значение всех полей «ФИО» на слова «Удалено из БД».
Попробуйте удалить отношение «Директора_Тест». Убедитесь, что оно
ещё существует и что значения полей «ФИО» поменялись при помощи
запроса: SELECT * FROM dbo. Директора_Тест. Удалите триггер.
Создайте хранимую процедуру, которая удаляет отношение
«Директора_Тест». Запустите процедуру, затем удалите её.
ç

5. Напишите DDL триггер, который запрещает изменение заданного поля,


используемого для связи между таблицами.
CREATE TRIGGER refferencies ON DATABASE
FOR ALTER_TABLE
AS begin
IF(EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
LIKE '%drop constraint%')
ROLLBACK TRANSACTION
END
GO
ALTER TABLE Виды_проекта ADD CONSTRAINT ddl_check CHECK (Количество_участников < 20)
ALTER TABLE Виды_проекта DROP CONSTRAINT ddl_check
GO
DISABLE TRIGGER refferencies ON DATABASE
DROP TRIGGER refferencies ON DATABASE

6. Напишите DDL триггер, который при изменении свойств определенного


поля, сделал бы автоматически схожие изменения в остальных таблицах.
CREATE TRIGGER change ON DATABASE
FOR ALTER_TABLE
AS begin
DECLARE @option NVARCHAR(max)
SET @option = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)
[1]','nvarchar(max)')
EXEC @option
SET @option = 'ALTER TABLE Проекта DROP COLUMN ID_директора'
EXEC @option
END

GO
ALTER TABLE dbo.Директора
DROP COLUMN ID_директора;

ENABLE TRIGGER change ON DATABASE


DISABLE TRIGGER change ON DATABASE
DROP TRIGGER change ON DATABASE
7. Напишите триггер, который запрещает изменение схемы базы данных
вне рабочего времени.
CREATE TRIGGER timechanger ON DATABASE
FOR ALTER_TABLE
AS
BEGIN
DECLARE @start_day TIME, @stop_day TIME, @now TIME
SET @start_day=convert(varchar(10),'09:00:00',108)
SET @stop_day=convert(varchar(10),'21:00:00',108)
SET @now = convert(varchar(10),GETDATE(),108)
IF (@now<@start_day) OR (@now > @stop_day)
BEGIN
PRINT N'Сейчас не рабочее время!'
ROLLBACK TRANSACTION
END
END
GO
ENABLE TRIGGER timechanger ON DATABASE
GO
ALTER TABLE [Проекта]
ADD testrow int NULL
ALTER TABLE [Проекта]
DROP COLUMN testrow
GO
DISABLE TRIGGER timechanger ON DATABASE
GO
DROP TRIGGER timechanger ON DATABASE

8. Напишите LOGON триггер, который запрещает заданному


пользователю вход в систему, если у него уже есть 3 активных
подключения с данным логином к одному экземпляру SQL Server. Триггер
должен считать количество активных подключений для данного логина из
системного представления sys.dm_exec_sessions.
USE master
GO
CREATE LOGIN login WITH PASSWORD = '1111',
CHECK_EXPIRATION = ON;

GO
GRANT VIEW SERVER STATE TO login;

CREATE TRIGGER connection_limit_trigger


ON ALL SERVER WITH EXECUTE AS 'login'
FOR LOGON
AS
BEGIN
IF ORIGINAL_LOGIN()= 'login' AND
(SELECT COUNT(*) FROM sys.dm_exec_sessions
WHERE is_user_process = 1 AND
original_login_name = 'login') > 3
ROLLBACK
END

Выводы:
После выполнения данной лабораторной работы я научился создавать и
использовать пользовательские функции, хранимые процедуры и триггеры
в SQL Server.