- •Аннотация
- •Содержание
- •Введение
- •1. Формулировка задания
- •1.1. Задание
- •1.2. Структура идз
- •Описание предметной области
- •Проектирование базы данных
- •Создание бАзы данных
- •Создание таблиц и ограничений целостности
- •Заполнение таблиц данными
- •Заполнение таблицы «Staff» (Сотрудники)
- •Заполнение таблицы «Tables» (Столы):
- •Заполнение таблицы «Categories» (Категории)
- •Заполнение таблицы «MenuItems» (Меню)
- •Заполнение таблицы «Orders» (Заказы)
- •Заполнение таблицы «OrderItems» (Позиции заказа)
- •Заполнение таблицы «Payments» (Платежи)
- •Разработка объектов промежуточного слоя
- •Хранимые процедуры
- •Процедура «CreateOrder» для создания нового заказа
- •Процедура «AddItemToOrder» для добавления позиций в заказ
- •Процедура «SetOrderWaitingForPayment» для перевода заказа в статус ожидания оплаты
- •Процедура «PayOrder» для оплаты заказа
- •Представления
- •Представление «ActiveOrders» для просмотра активных заказов
- •Представление «WaiterDailyRevenue», показывающее выручку, принесённую каждым из официантов
- •Представление «DailyOrderStats», показывающее по дням заработок ресторана, оплаченные заказы, средний чек
- •Представление «OrdersByWaiterStatus», показывающее количество заказов, обслуженных каждым из официантов по статусам заказа
- •Функции
- •Скалярная функция «OrderTotal» для подсчета стоимости заказа
- •Табличная функция «GetOrdersWithTotal», которая возвращает блюда по заказам
- •Табличная функция «GetMenuItemsByAvailability», показывающая оставшиеся блюда
- •Табличная функция «GetLastOrderItems» возвращающая последние блюда в заказах
- •Скалярная функция «MenuItemSalesPaid» для подсчета проданных позиций блюд в день
- •Разработка триггеров
- •Триггер «InsertWaiterTable» для вставки в таблицу WaiterTables, когда происходит заказ
- •Триггер «CheckStock», уменьшающий количество блюд в MenuItems и предупреждающий, если блюда закончились
- •Триггер «PreventWaitingPaymentWithoutItems», проверяющий пустой заказ
- •Разработка стратегии резервного копирования и восстановления
- •Процедура полного резервного копирования
- •Процедура дифференциального резервного копирования
- •Процедура резервного копирования журнала транзакций
- •Процедура тестирования всех бэкапов
- •Автоматизация через sql server agent
- •Процедура восстановления
- •Заключение
- •Список использованных источников
Триггер «PreventWaitingPaymentWithoutItems», проверяющий пустой заказ
Запрос:
CREATE OR ALTER TRIGGER trg_PreventWaitingPaymentWithoutItems
ON Orders
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT 1
FROM inserted i
JOIN deleted d ON i.OrderID = d.OrderID
WHERE i.Status = 'Ожидает оплаты' AND d.Status <> 'Ожидает оплаты'
)
BEGIN
IF EXISTS (
SELECT 1
FROM inserted i
LEFT JOIN OrderItems oi ON i.OrderID = oi.OrderID
GROUP BY i.OrderID
HAVING COUNT(oi.ItemID) = 0
)
BEGIN
RAISERROR('Невозможно перевести заказ в "Ожидает оплаты": в заказе нет блюд.', 16, 1);
RETURN;
END
END
UPDATE o
SET o.Status = i.Status,
o.Notes = i.Notes,
o.TableID = i.TableID,
o.WaiterID = i.WaiterID
FROM Orders o
JOIN inserted i ON o.OrderID = i.OrderID;
END;
GO
Пример использования
Пустой заказ
Создаем который не будет заполнен блюдами, после чего попытаемся его перевести в статус ожидания оплаты:
DECLARE @OrderID INT;
EXEC rest.CreateOrder
@TableID = 5,
@WaiterID = 4,
@Notes = 'Разделить блюдо на две порции',
@NewOrderID = @OrderID OUTPUT;
PRINT 'Создан заказ с ID = ' + CAST(@OrderID AS NVARCHAR(10));
EXEC rest.SetOrderWaitingForPayment @OrderID = 10;
Ошибка выполнения запроса (рис. 45).
Рисунок 45. Результат работы триггера на проверку заказов без блюд
Правильный запрос
EXEC rest.AddItemToOrder
@OrderID = 10,
@ItemID = 5,
@Quantity = 1;
EXEC rest.SetOrderWaitingForPayment @OrderID = 10;
EXEC rest.PayOrder
@OrderID = 10,
@Amount = 6000,
@PaymentMethod = 'Наличные';
При корректном запросе оплата заказа успешно проходит (рис. 45).
Рисунок 45. Результат работы триггера на проверку корректных заказов
Разработка стратегии резервного копирования и восстановления
Разработанная система представляет собой комплексное решение для резервного копирования и восстановления базы данных ресторана. Она построена по многоуровневой модели, включающей три типа бэкапов и полностью автоматизированный процесс восстановления.
Процедура полного резервного копирования
Повтор при сбоях реализован через встроенный механизм 3-х попыток с задержкой 5 секунд между ними для надежности. Уникальные имена файлов обеспечиваются автоматическим формированием с использованием timestamp, что предотвращает конфликты и упорядочивает версии. Сжатие данных задействует технологию COMPRESSION для значительной экономии дискового пространства без потери информации. Изоляция файлов достигается за счет хранения в отдельной папке D:\Backup\FULL.
USE master;
GO
CREATE OR ALTER PROCEDURE dbo.sp_Restaurant_BackupFull
@RetryCount INT = 3
AS
BEGIN
SET NOCOUNT ON;
DECLARE @BackupPath NVARCHAR(500);
DECLARE @Attempt INT = 1;
DECLARE @Success BIT = 0;
DECLARE @ErrorMessage NVARCHAR(4000);
SET @BackupPath = N'D:\Backup\FULL\DataBase_Restaurant_FULL_' +
REPLACE(CONVERT(NVARCHAR(20), GETDATE(), 120), ':', '-') + '.bak';
PRINT 'ПОЛНОЕ РЕЗЕРВНОЕ КОПИРОВАНИЕ БАЗЫ RESTAURANT';
PRINT 'Файл: ' + @BackupPath;
WHILE @Attempt <= @RetryCount AND @Success = 0
BEGIN
BEGIN TRY
PRINT 'Попытка ' + CAST(@Attempt AS NVARCHAR) + '...';
BACKUP DATABASE [DataBase_Restaurant]
TO DISK = @BackupPath
WITH FORMAT,
INIT,
NAME = N'Restaurant - Full Database Backup',
STATS = 10,
COMPRESSION;
PRINT 'Бэкап успешно создан!';
SET @Success = 1;
END TRY
BEGIN CATCH
SET @ErrorMessage = ERROR_MESSAGE();
PRINT 'Ошибка: ' + @ErrorMessage;
SET @Attempt = @Attempt + 1;
IF @Attempt <= @RetryCount
BEGIN
PRINT 'Повторная попытка через 5 секунд...';
WAITFOR DELAY '00:00:05';
END
END CATCH
END
IF @Success = 0
RAISERROR('Не удалось выполнить резервное копирование после %d попыток.', 16, 1, @RetryCount);
END;
GO
