Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

БД 6 Отчёт

.docx
Скачиваний:
1
Добавлен:
09.07.2024
Размер:
33.75 Кб
Скачать

Министерство образования Республики Беларусь

БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ

ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ

Кафедра экономической информатики

Лабораторная работа №7

Курсоры и триггеры в языке Transact-SQL

Вариант 6

Выполнил:

студент группы

Проверил:

доцент

кафедры ЭИ

Бутов А.А.

Минск 2023

Цель работы

  1. Ознакомиться с использованием курсоров в языке Transact-SQL.

  2. Освоить способы создания триггеров в языке Transact-SQL.

Задачи

  1. Объявление и открытие курсора с целью манипулирования строками набора данных.

  2. Закрытие и освобождение курсора.

  3. Реализация бизнес-правил с помощью триггеров.

  4. Получение информации об изменениях в данных с помощью триггерных таблиц inserted и deleted.

  5. Использование команд управления транзакциями.

Разработанный скрипт имеет вид:

USE Склад_218

GO

/*1.Создайте для таблицы Заказ триггер tr_Set_СрокПоставки, с помощью которого в этой таблице будет автоматически устанавливаться значение поля СрокПоставки при вставке новой записи и при обновлении поля ДатаЗаказа следующим образом:

- если цена товара определена в белорусских рублях, то срок поставки равен дате заказа плюс 3 дня;

- если цена товара определена в российских рублях или украинских гривнах, то срок поставки равен дате заказа плюс 7 дней;

- если цена товара определена в долларах США или евро, то срок поставки равен дате заказа плюс 10 дней;

- если цена товара определена в валюте, отличной от указанных выше валют, то срок поставки равен дате заказа плюс 14 дней.*/

CREATE TRIGGER tr_Set_СрокПпоставки

ON Заказ

FOR INSERT, UPDATE

AS

IF UPDATE(ДатаЗаказа)

DECLARE @OrderCode INT;

DECLARE @CurrencyCode VARCHAR(3);

SELECT @CurrencyCode = Т.КодВалюты

FROM inserted И

INNER JOIN Товар Т ON И.КодТовара = Т.КодТовара;

SELECT @OrderCode = КодЗаказа

FROM inserted;

DECLARE @Days INT;

IF @CurrencyCode = 'BYR'

SET @Days = 3;

ELSE IF @CurrencyCode = 'RUR' OR @CurrencyCode = 'GRV'

SET @Days = 7;

ELSE IF @CurrencyCode = 'USD' OR @CurrencyCode = 'EUR'

SET @Days = 10;

ELSE

SET @Days = 14;

UPDATE Заказ

SET СрокПоставки = ДатаЗаказа + @Days

WHERE КодЗаказа = @OrderCode;

GO

SELECT* FROM Заказ

UPDATE Заказ

SET ДатаЗаказа = '2020.02.01'

WHERE КодЗаказа = 5;

SELECT* FROM Заказ

/*2. Добавьте в базу данных новую таблицу Отпуск, которая снабжена связью типа «один к одному» с таблицей Товар:*/

--CREATE TABLE Отпуск (

-- КодТовара INT PRIMARY KEY,

-- Наименование VARCHAR(50) NOT NULL,

-- ВсегоЗаказано NUMERIC(12, 3) NULL,

-- CONSTRAINT FK_Отпуск_Товар FOREIGN KEY (КодТовара)

-- REFERENCES Товар ON UPDATE CASCADE

--);

--GO

/*Создайте для таблицы Заказ триггер tr_Кол _ЗаказанногоТовара, с помощью которого в таблице Отпуск будет автоматически обновляться информация о суммарном количестве заказанного товара.

Триггер должен срабатывать при операциях вставки и удаления строк в таблице Заказ, а также при обновлении в ней поля Количество. Если в таблице Отпуск еще нет строки,

подлежащей корректировке (а так вначале и будет), то должна быть выполнена операция вставки новой строки,

в которой в поле ВсегоЗаказано записывается суммарное количество заказанного товара, подсчитанное на основе всех строк таблицы Заказ, связанных с данным товаром.*/

ALTER TRIGGER tr_Кол_ЗаказанногоТовараа

ON Заказ

FOR INSERT, UPDATE, DELETE

AS

IF UPDATE(Количество)

DECLARE @Rows INT;

DECLARE @ProductCode INT;

DECLARE @ProductName VARCHAR(50);

DECLARE @Count INT;

SELECT @ProductCode = И.КодТовара, @ProductName = Т.Наименование

FROM inserted И

INNER JOIN Товар Т ON И.КодТовара = Т.КодТовара;

SELECT @Count = SUM(Количество)

FROM Заказ

WHERE КодТовара = @ProductCode;

SELECT @Rows = COUNT(*)

FROM Отпуск О

INNER JOIN Товар Т

ON О.КодТовара = Т.КодТовара

INNER JOIN inserted И

ON И.КодТовара = Т.КодТовара

WHERE И.КодТовара = О.КодТовара;

IF @Rows = 0

INSERT INTO Отпуск VALUES (@ProductCode, @ProductName, @Count);

ELSE

UPDATE Отпуск SET ВсегоЗаказано = @Count

WHERE КодТовара = @ProductCode;

GO

SELECT SUM(Количество) FROM Заказ

WHERE КодТовара = 110;

SELECT * FROM Отпуск

SELECT * FROM Товар

SELECT* FROM Поставщик

INSERT INTO Заказ (КодКлиента, КодТовара, Количество, КодПоставщика) VALUES (3, 110, 20, 123);

INSERT INTO Заказ (КодКлиента, КодТовара, Количество, КодПоставщика) VALUES (1, 112, 15, 234);

GO

/*3. Создайте хранимую процедуру pr_Стоимость_ВалютаИнтервал для решения более общей задачи по сравнению с задачей, рассмотренной в разделе I, а именно:

необходимо подсчитать суммарную стоимость всех товаров, заказанных в течение указанного интервала времени, однако не в национальной валюте, а в валюте, указанной пользователем

(в частности, может быть указана и национальная валюта). Эта процедура должна иметь три входных параметра (@КодВалюты, @НачалоИнтервала, @КонецИнтервала) и один выходной параметр (@Стоимость).*/

Create PROCEDURE pr_Стоимость_ВалютаИнтерваffл

(@КодВалюты VARCHAR(3),

@НачалоИнтервала DATE,

@КонецИнтервала DATE,

@Стоимость MONEY OUTPUT)

AS

DECLARE @Rate SMALLMONEY;

SELECT @Rate = КурсВалюты

FROM Валюта

WHERE @КодВалюты = КодВалюты;

SET @Стоимость = 0;

DECLARE @OrderPrice MONEY;

DECLARE myCursor CURSOR LOCAL STATIC

FOR

SELECT з.Количество * т.Цена / в.КурсВалюты * @Rate

FROM Заказ з

JOIN Товар т

ON з.КодТовара = т.КодТовара

JOIN Валюта в

ON т.КодВалюты = в.КодВалюты

WHERE з.ДатаЗаказа BETWEEN @НачалоИнтервала AND @КонецИнтервала;

OPEN myCursor;

FETCH FIRST FROM myCursor INTO @OrderPrice;

WHILE @@FETCH_STATUS = 0

BEGIN

SET @Стоимость = @Стоимость + @OrderPrice;

FETCH NEXT FROM myCursor INTO @OrderPrice;

END;

CLOSE myCursor;

DEALLOCATE myCursor;

GO

SELECT * FROM Заказ

DECLARE @Price MONEY;

EXEC pr_Стоимость_ВалютаИнтервал 'BYR', '2021.05.09', '2022.01.01', @Price OUTPUT;

SELECT @Price;

/*4. Добавьте в таблицу Регион две новые строки, используя следующие команды:*/

INSERT INTO Регион

VALUES (102, 'Россия', '', 'Москва', 'пр.Калинина, 50',

'339-62- 10', '456456456');

INSERT INTO Регион

VALUES (106, 'Литва', '', 'Вильнюс', 'ул.Чурлёниса, 19', NULL,

'55555555');

GO

/*Разработайте программный код (не обязательно в виде хранимой процедуры), который формирует таблицу следующего вида:

Страна Число клиентов Число поставщиков

. . . . . . . . .

При этом используйте созданную при выполнении предыдущей лабораторной работы хранимую процедуру pr_КлиентПоставщик_СтранаИнтервал, которая подсчитывает, сколько различных клиентов и

поставщиков из указанной страны фигурирует в таблице Заказ (за указанный интервал времени). Эта хранимая процедура должна применяться для формирования каждой строки в указанной выше таблице.

Число строк этой таблицы должно равняться числу различных стран, фигурирующих в таблице Регион.*/

DROP PROC clientsSuppliersByCountry

GO

CREATE PROCEDURE clientsSuppliersByCountryy

(@НачалоИнтервала DATE,

@КонецИнтервала DATE)

AS

DECLARE @Country VARCHAR(20);

DECLARE @ClientsNumber INT;

DECLARE @SuppliersNumber INT;

DECLARE @table TABLE (

Страна VARCHAR(20),

ЧислоКлиентов INT,

ЧислоПоставщиков INT);

DECLARE myCursor CURSOR LOCAL STATIC

FOR

SELECT DISTINCT Страна

FROM Регион;

OPEN myCursor;

FETCH FIRST FROM myCursor INTO @Country;

WHILE @@FETCH_STATUS = 0

BEGIN

EXEC pr_КлиентПоставщик_СтранаИнтервал @Country, @НачалоИнтервала, @КонецИнтервала, @ClientsNumber OUTPUT, @SuppliersNumber OUTPUT;

INSERT INTO @table VALUES (@Country, @ClientsNumber, @SuppliersNumber);

FETCH NEXT FROM myCursor INTO @Country;

END;

SELECT * FROM @table;

CLOSE myCursor;

DEALLOCATE myCursor;

GO

EXEC clientsSuppliersByCountryy '2020.10.10', '2021.10.10';

/*5. Создайте таблицу Протокол со структурой, приведенной ниже, в которой должны автоматически фиксироваться все действия, вызванные вставкой, обновлением или удалением данных в таблице Товар. Каждая команда, изменяющая содержимое таблицы Товар, должна быть отражена отдельной строкой в таблице Протокол.

Номер ДатаВремя Пользователь Действие ЧислоСтрок

. . . . . . . . . . . . . . .

Здесь столбец Номер является автоинкрементным первичным ключом. В столбце Действие указывается одна из трех возможных операций с данными: «Вставка», «Обновление», «Удаление». Столбец ЧислоСтрок будет содержать данные о числе вставленных, либо обновленных, либо удаленных строк в таблице Товар.

Усложненный вариант. Таблица Протокол должна включать в себя еще один столбец КодыТоваров, в котором указываются коды товаров, фигурирующие во вставленных, обновленных или удаленных строках.*/

CREATE TABLE Пdgdроотокол (

Номер INT IDENTITY(1,1) PRIMARY KEY,

ДатаВремя DATETIME NOT NULL,

Пользователь VARCHAR(80) NOT NULL,

Действие VARCHAR(10) NOT NULL,

ЧислоСтрок INT NOT NULL

);

GO

CREATE TRIGGER tr_insertProвdddd

ON Товар

FOR INSERT

AS

DECLARE @RowsNumber INT;

SELECT @RowsNumber = COUNT(*)

FROM inserted;

INSERT INTO Протоколл VALUES (GETDATE(), SUSER_NAME(), 'Вставка', @RowsNumber);

GO

CREATE TRIGGER tr_updProjjdв

ON Товар

FOR UPDATE

AS

DECLARE @RowsNumber1 INT;

SELECT @RowsNumber1 = COUNT(*)

FROM inserted;

INSERT INTO Протоколл VALUES (GETDATE(), SUSER_NAME(), 'Обновление', @RowsNumber1);

GO

CREATE TRIGGER tr_deдjjlProdd

ON Товар

FOR DELETE

AS

DECLARE @RowsNumber2 INT;

SELECT @RowsNumber2 = COUNT(*)

FROM deleted;

INSERT INTO Протоколл VALUES (GETDATE(), SUSER_NAME(), 'Удаление', @RowsNumber2);

GO

SELECT* FROM Пdgdроотокол;

SELECT* FROM Товар

INSERT INTO Товар (КодТовара, Наименование, Цена, КодВалюты, Расфасован) VALUES (555, 'Шуруповерт', 150, 'BYR', 'Да');

DELETE FROM Товар WHERE КодТовара = 222;

/*6. Доведите до завершения рассмотренную выше в виде примера задачу корректировки значений полей Стоимость и СтоимостьНВ в таблице Заказ.

Значения этих полей должны автоматически обновляться не только при изменении цены товара (как было реализовано в примере), но и при изменении количества заказанного товара,

а также вставке новых строк в таблицу Заказ. Кроме того, значение столбца СтоимостьНВ должно автоматически обновляться также при изменении курса соответствующей валюты.*/

GO

CREATE TRIGGER tr_Товарh_Ценa

ON Товар

FOR INSERT, UPDATE

AS

IF UPDATE(Цена)

BEGIN

DECLARE @КодТовара INT, @Цена MONEY, @ЦенаНВ MONEY

DECLARE myCursor CURSOR LOCAL STATIC

FOR

SELECT и.КодТовара, и.Цена, и.Цена * в.КурсВалюты

FROM inserted и

JOIN Валюта в

ON и.КодВалюты = в.КодВалюты;

OPEN myCursor;

FETCH FIRST FROM myCursor INTO @КодТовара, @Цена, @ЦенаНВ;

WHILE @@FETCH_STATUS = 0

BEGIN

UPDATE Заказ

SET Стоимость = Количество * @Цена, СтоимостьНВ = Количество * @ЦенаНВ

WHERE КодТовара = @КодТовара;

FETCH NEXT FROM myCursor INTO @КодТовара, @Цена, @ЦенаНВ;

END;

CLOSE myCursor;

DEALLOCATE myCursor;

END;

GO

SELECT * FROM Товар

UPDATE Товар

SET Цена = Цена + 10;

GO

SELECT * FROM Товар

CREATE TRIGGER tr_Товаар_Количествооо

ON Заказ

FOR INSERT, UPDATE

AS

IF UPDATE(Количество)

BEGIN

DECLARE @КодЗаказа INT, @Цена MONEY, @ЦенаНВ MONEY

DECLARE myCursor CURSOR LOCAL STATIC

FOR

SELECT и.КодЗаказа, т.Цена, т.Цена * в.КурсВалюты

FROM inserted и

JOIN Товар т

ON и.КодТовара = т.КодТовара

JOIN Валюта в

ON т.КодВалюты = в.КодВалюты;

OPEN myCursor;

FETCH FIRST FROM myCursor INTO @КодЗаказа, @Цена, @ЦенаНВ;

WHILE @@FETCH_STATUS = 0

BEGIN

UPDATE Заказ

SET Стоимость = Количество * @Цена, СтоимостьНВ = Количество * @ЦенаНВ

WHERE КодЗаказа = @КодЗаказа;

FETCH NEXT FROM myCursor INTO @КодЗаказа, @Цена, @ЦенаНВ;

END;

CLOSE myCursor;

DEALLOCATE myCursor;

END;

GO

SELECT * FROM Заказ

UPDATE Заказ

SET Количество = 5

SELECT * FROM Заказ

WHERE КодЗаказа = 9;

GO

Соседние файлы в предмете Базы данных