Загрузка данных
---------------------------------------------------------
-- 1. УДАЛЕНИЕ СТАРЫХ ТАБЛИЦ (в правильном порядке)
---------------------------------------------------------
DROP TABLE IF EXISTS purchase_analytics;
DROP TABLE IF EXISTS awaiting_stock;
DROP TABLE IF EXISTS purchase_list;
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS product_prices;
DROP TABLE IF EXISTS products;
DROP TABLE IF EXISTS buyers;
DROP TABLE IF EXISTS categories;
DROP TABLE IF EXISTS payment_methods;
DROP TABLE IF EXISTS order_statuses;
GO
---------------------------------------------------------
-- 2. СОЗДАНИЕ ТАБЛИЦ
---------------------------------------------------------
-- Статусы заказов
CREATE TABLE order_statuses (
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(50) NOT NULL UNIQUE
);
-- Методы оплаты
CREATE TABLE payment_methods (
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(50) NOT NULL
);
-- Категории товаров
CREATE TABLE categories (
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(100) NOT NULL
);
-- Товары
CREATE TABLE products (
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(200) NOT NULL,
category_id INT NOT NULL REFERENCES categories(id),
release_date DATE,
specification NVARCHAR(MAX),
availability INT DEFAULT 0 CHECK (availability >= 0),
current_price DECIMAL(10,2), -- Заполняется автоматически триггером
release_price DECIMAL(10,2),
lastyear_price DECIMAL(10,2)
);
-- История изменения цен
CREATE TABLE product_prices (
id INT IDENTITY(1,1) PRIMARY KEY,
product_id INT NOT NULL REFERENCES products(id),
price DECIMAL(10,2) NOT NULL CHECK (price > 0),
set_date DATETIME DEFAULT GETDATE()
);
-- Покупатели
CREATE TABLE buyers (
id INT IDENTITY(1,1) PRIMARY KEY,
name_client NVARCHAR(150) NOT NULL,
payment_method_id INT REFERENCES payment_methods(id),
payment_details NVARCHAR(255),
total_spent DECIMAL(12,2) DEFAULT 0,
reg_date DATE DEFAULT GETDATE()
);
-- Заказы
CREATE TABLE orders (
id INT IDENTITY(1,1) PRIMARY KEY,
product_id INT NOT NULL REFERENCES products(id),
buyer_id INT NOT NULL REFERENCES buyers(id),
order_date DATETIME DEFAULT GETDATE(),
quantity INT NOT NULL CHECK (quantity > 0),
price_at_order DECIMAL(10,2),
order_price AS (quantity * price_at_order) PERSISTED,
status_id INT DEFAULT 1 REFERENCES order_statuses(id) -- 1 = Оформлен
);
-- Список купленных товаров (заполняется триггером)
CREATE TABLE purchase_list (
id INT IDENTITY(1,1) PRIMARY KEY,
buyer_id INT NOT NULL REFERENCES buyers(id),
order_id INT NOT NULL REFERENCES orders(id),
product_id INT NOT NULL REFERENCES products(id),
quantity INT NOT NULL,
paid_price DECIMAL(10,2) NOT NULL,
purchase_date DATETIME DEFAULT GETDATE()
);
-- Ожидание поступления (поставки)
CREATE TABLE awaiting_stock (
id INT IDENTITY(1,1) PRIMARY KEY,
product_id INT NOT NULL REFERENCES products(id),
expected_date DATE,
quantity INT NOT NULL CHECK (quantity > 0),
note NVARCHAR(255)
);
-- Аналитика покупок (заполняется триггером)
CREATE TABLE purchase_analytics (
id INT IDENTITY(1,1) PRIMARY KEY,
product_id INT NOT NULL REFERENCES products(id),
category_id INT NOT NULL REFERENCES categories(id),
period_month INT NOT NULL CHECK (period_month BETWEEN 1 AND 12),
period_year INT NOT NULL,
total_sold INT DEFAULT 0,
total_revenue DECIMAL(12,2) DEFAULT 0,
avg_price AS (CASE
WHEN total_sold > 0 THEN CAST(total_revenue AS DECIMAL(12,2)) / total_sold
ELSE 0 END) PERSISTED,
UNIQUE (product_id, period_month, period_year)
);
GO
---------------------------------------------------------
-- 3. ТРИГГЕРЫ
---------------------------------------------------------
-- Триггер: Обновление актуальной цены в таблице товаров
CREATE TRIGGER trg_update_product_price
ON product_prices
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE p
SET current_price = i.price
FROM products p
INNER JOIN (
SELECT product_id, price,
ROW_NUMBER() OVER(PARTITION BY product_id ORDER BY set_date DESC, id DESC) as rn
FROM inserted
) i ON p.id = i.product_id AND i.rn = 1;
END;
GO
-- Триггер: Создание заказа (списание склада, начисление денег, аналитика)
CREATE TRIGGER trg_orders_insert
ON orders
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
-- Фиксируем цену на момент заказа
UPDATE o
SET price_at_order = p.current_price
FROM orders o
INNER JOIN inserted i ON o.id = i.id
INNER JOIN products p ON p.id = i.product_id;
-- Списываем товар со склада
UPDATE p
SET availability = availability - i.quantity
FROM products p
INNER JOIN inserted i ON p.id = i.product_id;
-- Запись в историю покупок
INSERT INTO purchase_list (buyer_id, order_id, product_id, quantity, paid_price, purchase_date)
SELECT i.buyer_id, i.id, i.product_id, i.quantity, ISNULL(i.quantity * p.current_price, 0), i.order_date
FROM inserted i
INNER JOIN products p ON p.id = i.product_id;
-- Увеличиваем общую сумму трат клиента
UPDATE b
SET total_spent = total_spent + ISNULL(i.quantity * p.current_price, 0)
FROM buyers b
INNER JOIN inserted i ON b.id = i.buyer_id
INNER JOIN products p ON p.id = i.product_id;
-- Обновляем аналитику продаж
MERGE purchase_analytics AS target
USING (
SELECT i.product_id, p.category_id,
MONTH(i.order_date) AS period_month,
YEAR(i.order_date) AS period_year,
i.quantity AS qty,
i.quantity * ISNULL(p.current_price, 0) AS revenue
FROM inserted i
INNER JOIN products p ON p.id = i.product_id
) AS src
ON target.product_id = src.product_id AND target.period_month = src.period_month AND target.period_year = src.period_year
WHEN MATCHED THEN
UPDATE SET total_sold = target.total_sold + src.qty, total_revenue = target.total_revenue + src.revenue
WHEN NOT MATCHED THEN
INSERT (product_id, category_id, period_month, period_year, total_sold, total_revenue)
VALUES (src.product_id, src.category_id, src.period_month, src.period_year, src.qty, src.revenue);
END;
GO
-- Триггер: Отмена заказа (возврат на склад и перерасчет)
CREATE TRIGGER trg_orders_cancel
ON orders
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(status_id)
BEGIN
-- 3 = ID статуса 'Отменён'
UPDATE products
SET availability = availability + d.quantity
FROM products p
INNER JOIN inserted i ON p.id = i.product_id
INNER JOIN deleted d ON d.id = i.id
WHERE i.status_id = 3 AND d.status_id != 3;
UPDATE buyers
SET total_spent = total_spent - (d.quantity * d.price_at_order)
FROM buyers b
INNER JOIN inserted i ON b.id = i.buyer_id
INNER JOIN deleted d ON d.id = i.id
WHERE i.status_id = 3 AND d.status_id != 3;
UPDATE purchase_analytics
SET total_sold = total_sold - d.quantity,
total_revenue = total_revenue - (d.quantity * d.price_at_order)
FROM purchase_analytics pa
INNER JOIN inserted i ON pa.product_id = i.product_id AND pa.period_month = MONTH(i.order_date) AND pa.period_year = YEAR(i.order_date)
INNER JOIN deleted d ON d.id = i.id
WHERE i.status_id = 3 AND d.status_id != 3;
END
END;
GO
---------------------------------------------------------
-- 4. ПЕРВИЧНОЕ ЗАПОЛНЕНИЕ ДАННЫМИ (БАЗА)
---------------------------------------------------------
INSERT INTO order_statuses (name) VALUES ('Оформлен'), ('Доставлен'), ('Отменён');
INSERT INTO payment_methods (name) VALUES ('Банковская карта'), ('Наличные'), ('PayPal'), ('Криптовалюта');
INSERT INTO categories (name) VALUES ('Смартфоны'), ('Ноутбуки'), ('Аксессуары'), ('Планшеты'), ('Комплектующие');
-- Добавляем товары (пока без актуальной цены)
INSERT INTO products (name, category_id, release_date, specification, availability, release_price, lastyear_price) VALUES
('iPhone 15 Pro', 1, '20230922', 'A17 Pro, 256GB, 48MP', 50, 99999, 95000),
('Samsung Galaxy S24', 1, '20240117', 'Snapdragon 8 Gen 3, 256GB', 40, 84999, 82000),
('MacBook Air M3', 2, '20240308', 'Apple M3, 8GB, 256GB SSD', 20, 124999, 121000),
('ASUS ROG Zephyrus G14', 2, '20240215', 'Ryzen 9, RTX 4060, 16GB', 15, 114999, 111000),
('AirPods Pro 2', 3, '20220923', 'ANC, H2 chip, MagSafe', 60, 24999, 21000),
('iPad Air M2', 4, '20240308', 'Apple M2, 11", 128GB', 25, 69999, 66000),
('RTX 4070 Ti', 5, '20230105', 'Ada Lovelace, 12GB GDDR6X', 10, 79999, 74000),
('USB-C Hub 7-in-1', 3, '20230601', 'HDMI 4K, USB 3.0 x3, SD', 100, 3499, 3100);
-- Устанавливаем цены. Триггер сам перенесет их в таблицу products!
INSERT INTO product_prices (product_id, price, set_date) VALUES
(1, 10, '20260612'), (2, 15, '20260613'), (3, 60, '20260614'),
(4, 90, '20260615'), (1, 15, '20260616'), (2, 16, '20260617'),
(3, 55, '20260618'), (4, 98, '20260619'), (1, 100, '20260620'),
(3, 90, '20260621'), (1, 110, '20260622'),
(5, 19999, '20260623'), (6, 64999, '20260623'), (7, 69999, '20260623'), (8, 2999, '20260623');
-- Добавляем покупателей
INSERT INTO buyers (name_client, payment_method_id, payment_details, reg_date) VALUES
('Иван Петров', 1, '**** **** **** 1234', '20240110'),
('Мария Сидорова', 1, '**** **** **** 5678', '20240215'),
('Алексей Козлов', 2, NULL, '20240301'),
('Екатерина Новикова', 3, 'e.novikova@paypal.com', '20240520'),
('Дмитрий Волков', 4, '1A2B3C...wallet', '20240611');
-- Поставки
INSERT INTO awaiting_stock (product_id, expected_date, quantity, note) VALUES
(7, '20260415', 10, 'Поставка из Европы'),
(3, '20260420', 5, 'Новая партия M3'),
(1, '20260501', 20, 'iPhone 15 Pro — пополнение склада');
-- Первые заказы клиентов (статус 1 ставится автоматически)
INSERT INTO orders (product_id, buyer_id, quantity) VALUES
(1, 1, 1),
(2, 2, 1);
GO
---------------------------------------------------------
-- 5. ПРИМЕР: КАК РАБОТАТЬ С БАЗОЙ (Добавление нужных таблиц)
---------------------------------------------------------
-- Шаг 1. Поступил новый товар. Добавляем его в базу (ID присвоится автоматически = 9)
INSERT INTO products (name, category_id, release_date, specification, availability)
VALUES ('Sony PlayStation 5 Pro', 5, '20251101', 'AMD Ryzen Zen 2, 2TB SSD', 10);
-- Шаг 2. Устанавливаем цену на новый товар (ID = 9)
INSERT INTO product_prices (product_id, price, set_date)
VALUES (9, 75000, GETDATE());
-- Шаг 3. Регистрируется новый покупатель
INSERT INTO buyers (name_client, payment_method_id, reg_date)
VALUES ('Сергей Иванов', 1, GETDATE());
-- Шаг 4. Покупатель (Сергей, допустим его ID = 6) заказывает этот товар (ID = 9) в количестве 2 шт.
-- Триггер сам спишет их со склада и посчитает сумму.
INSERT INTO orders (product_id, buyer_id, quantity)
VALUES (9, 6, 2);
-- Шаг 5. Курьер доставил заказ (допустим это заказ ID = 3). Меняем статус на 'Доставлен' (ID статуса = 2).
UPDATE orders SET status_id = 2 WHERE id = 3;
-- Шаг 6. Клиент передумал, заказ отменяем (ID статуса = 3).
-- Триггер вернет 2 приставки обратно на склад и заберет потраченные деньги из профиля клиента.
UPDATE orders SET status_id = 3 WHERE id = 3;