![](/user_photo/_userpic.png)
БД 6 Отчёт
.docxМинистерство образования Республики Беларусь
БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ
Кафедра экономической информатики
Лабораторная работа №7
Курсоры и триггеры в языке Transact-SQL
Вариант 6
Выполнил: |
студент группы
|
Проверил: |
доцент кафедры ЭИ Бутов А.А. |
Минск 2023
Цель работы
Ознакомиться с использованием курсоров в языке Transact-SQL.
Освоить способы создания триггеров в языке Transact-SQL.
Задачи
Объявление и открытие курсора с целью манипулирования строками набора данных.
Закрытие и освобождение курсора.
Реализация бизнес-правил с помощью триггеров.
Получение информации об изменениях в данных с помощью триггерных таблиц inserted и deleted.
Использование команд управления транзакциями.
Разработанный скрипт имеет вид:
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