- •Аннотация
- •Содержание
- •Введение
- •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
- •Процедура восстановления
- •Заключение
- •Список использованных источников
Скалярная функция «MenuItemSalesPaid» для подсчета проданных позиций блюд в день
Запрос:
CREATE FUNCTION rest.ufn_MenuItemSalesPaid (
@ItemID INT,
@SalesDate DATE
)
RETURNS INT
AS
BEGIN
DECLARE @Count INT;
SELECT @Count = SUM(oi.Quantity)
FROM rest.OrderItems oi
JOIN rest.Orders o ON oi.OrderID = o.OrderID
WHERE oi.ItemID = @ItemID
AND CAST(o.OrderDateTime AS DATE) = @SalesDate
AND o.Status = 'Оплачен';
RETURN ISNULL(@Count, 0);
END;
GO
Пример использования:
DECLARE @SalesCount INT;
SET @SalesCount = rest.ufn_MenuItemSalesPaid(5, '2025-12-04');
PRINT 'Блюдо с ItemID = 5 продано сегодня в количестве: ' + CAST(@SalesCount AS NVARCHAR(10));
Результат выполнения (рис. 40).
Рисунок 40. Результат работы функции подсчета блюд
Разработка триггеров
Триггер «InsertWaiterTable» для вставки в таблицу WaiterTables, когда происходит заказ
Запрос:
CREATE OR ALTER TRIGGER rest.trg_InsertWaiterTable
ON rest.Orders
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO rest.WaiterTables (StaffID, TableID, StartTime, EndTime)
SELECT i.WaiterID, i.TableID, GETDATE(), NULL
FROM inserted i
WHERE NOT EXISTS (
SELECT 1
FROM rest.WaiterTables wt
WHERE wt.StaffID = i.WaiterID
AND wt.TableID = i.TableID
AND wt.EndTime IS NULL
);
UPDATE wt
SET EndTime = GETDATE()
FROM rest.WaiterTables wt
JOIN inserted i ON wt.StaffID = i.WaiterID AND wt.TableID = i.TableID
JOIN rest.Orders o ON o.OrderID = i.OrderID
WHERE o.Status = 'Оплачен' AND wt.EndTime IS NULL;
END;
GO
После создания триггера было создано несколько заказов.
Примеры использования:
Выводим таблицу относительно столов
SELECT
s.StaffID,
s.FirstName,
s.LastName,
t.TableID,
t.TableNumber,
wt.StartTime,
wt.EndTime
FROM rest.Staff s
JOIN rest.WaiterTables wt ON s.StaffID = wt.StaffID
JOIN rest.Tables t ON wt.TableID = t.TableID
ORDER BY s.StaffID, t.TableID;
Результат выполнения запроса (рис. 41).
Рисунок 41. Пример работы представления сводной таблицы
Выводим таблицу относительно официантов
SELECT
t.TableID,
t.TableNumber,
s.StaffID,
s.FirstName,
s.LastName,
wt.StartTime,
wt.EndTime
FROM rest.Tables t
JOIN rest.WaiterTables wt ON t.TableID = wt.TableID
JOIN rest.Staff s ON wt.StaffID = s.StaffID
ORDER BY t.TableID, s.StaffID;
Результат выполнения (рис. 42).
Рисунок 42. Пример работы представления сводной таблицы
Триггер «CheckStock», уменьшающий количество блюд в MenuItems и предупреждающий, если блюда закончились
Запрос:
CREATE TRIGGER rest.trg_CheckStock
ON rest.OrderItems
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO rest.OrderItems (OrderID, ItemID, Quantity, UnitPrice, SpecialInstructions)
SELECT i.OrderID, i.ItemID, i.Quantity, i.UnitPrice, i.SpecialInstructions
FROM inserted i
JOIN rest.MenuItems m ON i.ItemID = m.ItemID
WHERE m.IsAvailable = 1
AND m.Stock >= i.Quantity;
UPDATE m
SET m.Stock = m.Stock - i.Quantity,
m.IsAvailable = CASE WHEN m.Stock - i.Quantity <= 0 THEN 0 ELSE 1 END
FROM rest.MenuItems m
JOIN inserted i ON m.ItemID = i.ItemID
WHERE m.IsAvailable = 1
AND m.Stock >= i.Quantity;
IF EXISTS (
SELECT 1
FROM inserted i
JOIN rest.MenuItems m ON i.ItemID = m.ItemID
WHERE m.IsAvailable = 0 OR m.Stock < i.Quantity
)
BEGIN
PRINT 'Внимание: некоторые выбранные блюда недоступны или количество порций ограничено.';
END
END;
GO
Пример использования:
Создаем заказ, где блюдо берется максимальное количество раз:
EXEC rest.AddItemToOrder
@OrderID = 6,
@ItemID = 7,
@Quantity = 8;
EXEC rest.SetOrderWaitingForPayment @OrderID = 6;
EXEC rest.PayOrder
@OrderID = 6,
@Amount = 6000,
@PaymentMethod = 'Наличные';
Запрос успешно выполнен (рис.43).
Рисунок 43. Выполнение запроса
Далее проверим таблицу MenuItems и увидим, что блюдо, которое мы заказывали максимальное количество раз, закончилось (рис. 44).
Рисунок 44. Результат работы триггера на уменьшение кол-ва блюд
