From 362cf5091dde2f73ceeb3fdef3ab8252b0cc6ad5 Mon Sep 17 00:00:00 2001 From: KomariK Date: Tue, 2 Dec 2025 09:36:12 +0300 Subject: [PATCH 1/4] Add files via upload --- koik.sql | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 koik.sql diff --git a/koik.sql b/koik.sql new file mode 100644 index 0000000..f6c4ac0 --- /dev/null +++ b/koik.sql @@ -0,0 +1,58 @@ +CREATE TABLE table_products +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + name TEXT NOT NULL CHECK ( name != '' ), + description TEXT NOT NULL CHECK ( description != '' ), + series TEXT NOT NULL CHECK ( series != '' ), + type_id INTEGER NOT NULL, + unit_id INTEGER NOT NULL, + manufacturer_id INTEGER NOT NULL, + purchase_price NUMERIC(7, 2) NOT NULL CHECK ( purchase_price > 0), + selling_price NUMERIC(7, 2) NOT NULL CHECK ( selling_price > purchase_price ), + unit_value NUMERIC(10, 2) NOT NULL CHECK ( unit_value > 0 ), + production_date DATE NOT NULL, + expiration_date DATE NOT NULL CHECK ( expiration_date > production_date ), + FOREIGN KEY (type_id) REFERENCES table_types (id), + FOREIGN KEY (unit_id) REFERENCES table_units (id), + FOREIGN KEY (manufacturer_id) REFERENCES table_manufacturers (id) +); + +-- Таблицы продаж +CREATE TABLE table_salespoint +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + name TEXT NOT NULL CHECK ( name != '' ), + address TEXT NOT NULL CHECK ( address != '' ) +); + +CREATE TABLE table_online_purchases +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + product_code INTEGER NOT NULL, + id_delivery_salespoint INTEGER NOT NULL, + payment PAYMENT_METHOD NOT NULL, + FOREIGN KEY (id_delivery_salespoint) REFERENCES table_salespoint (id) +); + +CREATE TABLE table_offline_purchases +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + salespoint_id INTEGER, + client_id INTEGER NOT NULL DEFAULT 0, + employee_id INTEGER NOT NULL, + FOREIGN KEY (client_id) REFERENCES table_clients (id), + FOREIGN KEY (employee_id) REFERENCES table_employees (id), + FOREIGN KEY (salespoint_id) REFERENCES table_salespoint (id) +); + +CREATE TABLE table_purchases +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + product_id INTEGER NOT NULL, + purchase_date DATE NOT NULL, + online_purchase_id INTEGER CHECK ( online_purchase_id IS NULL OR online_purchase_id = 0 ) DEFAULT 0, + offline_purchase_id INTEGER CHECK ( offline_purchase_id IS NULL OR offline_purchase_id = 0 ) DEFAULT 0, + FOREIGN KEY (online_purchase_id) REFERENCES table_online_purchases (id), + FOREIGN KEY (offline_purchase_id) REFERENCES table_offline_purchases (id), + FOREIGN KEY (product_id) REFERENCES table_products (id) +); \ No newline at end of file From f453222fcf2375738224684e0d99e9f792744d38 Mon Sep 17 00:00:00 2001 From: KomariK Date: Tue, 2 Dec 2025 09:49:18 +0300 Subject: [PATCH 2/4] Add files via upload --- koik.sql | 149 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 39 deletions(-) diff --git a/koik.sql b/koik.sql index f6c4ac0..9764cff 100644 --- a/koik.sql +++ b/koik.sql @@ -1,58 +1,129 @@ -CREATE TABLE table_products -( +--region Enums +CREATE TYPE PAYMENT_METHOD AS ENUM ('pay_after_receiving', 'pay_after_buying'); +CREATE TYPE SEX AS ENUM ('m', 'f'); +--endregion + +--region Core Tables (независимые) +CREATE TABLE table_emails ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + email TEXT NOT NULL CHECK (email != '' AND email ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$') +); + +CREATE TABLE table_phone_numbers ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + phone_number TEXT NOT NULL CHECK (phone_number != '' AND length(phone_number) >= 10) +); + +CREATE TABLE table_units ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + unit_type TEXT NOT NULL CHECK (unit_type != '' AND unit_type !~* '^\s+|\s+$') +); + +CREATE TABLE table_product_types ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + name TEXT NOT NULL CHECK (name != '' AND name !~* '^\s+|\s+$') +); + +CREATE TABLE table_salespoint ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + address TEXT NOT NULL CHECK (address != '' AND address !~* '^\s+|\s+$'), + name TEXT NOT NULL CHECK (name != '' AND name !~* '^\s+|\s+$') +); +--endregion + +--region Reference Tables (зависят от core) +CREATE TABLE table_manufacturers ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + name TEXT NOT NULL CHECK (name != ''), + address TEXT NOT NULL CHECK (address != ''), + phone_number TEXT NOT NULL CHECK (phone_number != ''), + website TEXT NOT NULL CHECK (website ~ '^https?://'), + manufacture_country TEXT NOT NULL CHECK (manufacture_country != ''), + brand TEXT NOT NULL CHECK (brand != ''), + license TEXT NOT NULL CHECK (license != '') +); + +CREATE TABLE table_persons ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + name TEXT NOT NULL CHECK (name != '' AND name !~* '^\s+|\s+$'), + surname TEXT NOT NULL CHECK (surname != '' AND surname !~* '^\s+|\s+$'), + patronymic TEXT NOT NULL CHECK (patronymic !~* '^\s+|\s+$'), + sex SEX NOT NULL, + email_id INTEGER NOT NULL, + phone_number_id INTEGER NOT NULL, + FOREIGN KEY (email_id) REFERENCES table_emails(id) ON DELETE RESTRICT, + FOREIGN KEY (phone_number_id) REFERENCES table_phone_numbers(id) ON DELETE RESTRICT, + UNIQUE(email_id, phone_number_id) +); + +CREATE TABLE table_products ( id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, - name TEXT NOT NULL CHECK ( name != '' ), - description TEXT NOT NULL CHECK ( description != '' ), - series TEXT NOT NULL CHECK ( series != '' ), type_id INTEGER NOT NULL, unit_id INTEGER NOT NULL, manufacturer_id INTEGER NOT NULL, - purchase_price NUMERIC(7, 2) NOT NULL CHECK ( purchase_price > 0), - selling_price NUMERIC(7, 2) NOT NULL CHECK ( selling_price > purchase_price ), - unit_value NUMERIC(10, 2) NOT NULL CHECK ( unit_value > 0 ), + name TEXT NOT NULL CHECK (name != ''), + description TEXT NOT NULL CHECK (description != ''), + series TEXT NOT NULL CHECK (series != ''), + purchase_price NUMERIC(7,2) NOT NULL CHECK (purchase_price > 0), + unit_value NUMERIC(10,2) NOT NULL CHECK (unit_value > 0), production_date DATE NOT NULL, - expiration_date DATE NOT NULL CHECK ( expiration_date > production_date ), - FOREIGN KEY (type_id) REFERENCES table_types (id), - FOREIGN KEY (unit_id) REFERENCES table_units (id), - FOREIGN KEY (manufacturer_id) REFERENCES table_manufacturers (id) + expiration_date DATE NOT NULL CHECK (expiration_date > production_date), + selling_price NUMERIC(7,2) NOT NULL CHECK (selling_price > purchase_price), + FOREIGN KEY (type_id) REFERENCES table_product_types(id), + FOREIGN KEY (unit_id) REFERENCES table_units(id), + FOREIGN KEY (manufacturer_id) REFERENCES table_manufacturers(id), + CHECK (selling_price > purchase_price) ); +--endregion --- Таблицы продаж -CREATE TABLE table_salespoint -( - id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, - name TEXT NOT NULL CHECK ( name != '' ), - address TEXT NOT NULL CHECK ( address != '' ) +--region Business Logic Tables (зависят от persons/products) +CREATE TABLE table_clients ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + person_id INTEGER NOT NULL UNIQUE, + discount NUMERIC(4,2) NOT NULL CHECK (discount >= 0 AND discount <= 100), + agreed_on_mailing BOOLEAN NOT NULL DEFAULT false, + FOREIGN KEY (person_id) REFERENCES table_persons(id) ON DELETE CASCADE ); -CREATE TABLE table_online_purchases -( +CREATE TABLE table_employees ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + person_id INTEGER NOT NULL UNIQUE, + position TEXT NOT NULL CHECK (position != ''), + hire_date DATE NOT NULL, + salary_in_rubles NUMERIC(7,2) NOT NULL CHECK (salary_in_rubles > 0), + FOREIGN KEY (person_id) REFERENCES table_persons(id) ON DELETE CASCADE +); +--endregion + +--region Purchase Tables (финальный уровень) +CREATE TABLE table_online_purchases ( id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, - product_code INTEGER NOT NULL, - id_delivery_salespoint INTEGER NOT NULL, - payment PAYMENT_METHOD NOT NULL, - FOREIGN KEY (id_delivery_salespoint) REFERENCES table_salespoint (id) + delivery_salespoint_id INTEGER NOT NULL, + product_id INTEGER NOT NULL, + payment_method PAYMENT_METHOD NOT NULL, + FOREIGN KEY (delivery_salespoint_id) REFERENCES table_salespoint(id), + FOREIGN KEY (product_id) REFERENCES table_products(id) ); -CREATE TABLE table_offline_purchases -( +CREATE TABLE table_offline_purchases ( id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, - salespoint_id INTEGER, client_id INTEGER NOT NULL DEFAULT 0, employee_id INTEGER NOT NULL, - FOREIGN KEY (client_id) REFERENCES table_clients (id), - FOREIGN KEY (employee_id) REFERENCES table_employees (id), - FOREIGN KEY (salespoint_id) REFERENCES table_salespoint (id) + salespoint_id INTEGER NOT NULL, + FOREIGN KEY (client_id) REFERENCES table_clients(id) ON DELETE SET DEFAULT, + FOREIGN KEY (employee_id) REFERENCES table_employees(id), + FOREIGN KEY (salespoint_id) REFERENCES table_salespoint(id) ); -CREATE TABLE table_purchases -( +CREATE TABLE table_purchases ( id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY NOT NULL, + online_purchase_id INTEGER, + offline_purchase_id INTEGER, product_id INTEGER NOT NULL, - purchase_date DATE NOT NULL, - online_purchase_id INTEGER CHECK ( online_purchase_id IS NULL OR online_purchase_id = 0 ) DEFAULT 0, - offline_purchase_id INTEGER CHECK ( offline_purchase_id IS NULL OR offline_purchase_id = 0 ) DEFAULT 0, - FOREIGN KEY (online_purchase_id) REFERENCES table_online_purchases (id), - FOREIGN KEY (offline_purchase_id) REFERENCES table_offline_purchases (id), - FOREIGN KEY (product_id) REFERENCES table_products (id) -); \ No newline at end of file + purchase_date DATE NOT NULL DEFAULT CURRENT_DATE, + CHECK ((online_purchase_id IS NULL) != (offline_purchase_id IS NULL)), + FOREIGN KEY (online_purchase_id) REFERENCES table_online_purchases(id), + FOREIGN KEY (offline_purchase_id) REFERENCES table_offline_purchases(id), + FOREIGN KEY (product_id) REFERENCES table_products(id) +); +--endregion From 788859896673b24cedd8890184dedd67c9940d3a Mon Sep 17 00:00:00 2001 From: KomariK Date: Mon, 8 Dec 2025 08:21:02 +0300 Subject: [PATCH 3/4] Add files via upload --- sport_shop.sql | 199 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 sport_shop.sql diff --git a/sport_shop.sql b/sport_shop.sql new file mode 100644 index 0000000..aec3a44 --- /dev/null +++ b/sport_shop.sql @@ -0,0 +1,199 @@ +SET TIME ZONE 'Europe/Moscow'; + +CREATE TYPE SEX AS ENUM ('M', 'F'); + +CREATE TYPE email_domain_enum AS ENUM ( + 'gmail.com', 'yandex.ru', 'mail.ru', 'outlook.com', + 'yahoo.com', 'rambler.ru', 'proton.me', 'icloud.com' + ); + + +CREATE TABLE table_manufacturers +( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name_manufacturer TEXT NOT NULL CHECK ( name_manufacturer != ''), + country TEXT NOT NULL CHECK ( country != '') +); + + +CREATE TABLE table_products +( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + manufacturer_id INT NOT NULL, + product_name TEXT NOT NULL CHECK ( product_name != '' ), + product_type TEXT NOT NULL CHECK ( product_type != '' ), + stock_quantity INT NOT NULL CHECK ( stock_quantity >= 0), + cost_price NUMERIC(12, 2) NOT NULL CHECK ( cost_price >= 0), + selling_price NUMERIC(12, 2) NOT NULL CHECK ( selling_price >= 0), + + FOREIGN KEY (manufacturer_id) REFERENCES table_manufacturers (id) +); + +CREATE TABLE table_clients +( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + first_name TEXT NOT NULL CHECK ( first_name != '' ), + patronymic TEXT, + last_name TEXT NOT NULL CHECK ( last_name != '' ), + sex SEX NOT NULL, + order_history TEXT, + discount_percent NUMERIC(5, 2) CHECK ( discount_percent BETWEEN 0 AND 70), + is_subscribed_newsletter BOOLEAN NOT NULL DEFAULT false +); + + +CREATE TABLE table_employees +( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + first_name TEXT NOT NULL CHECK ( first_name != '' ), + patronymic TEXT, + last_name TEXT NOT NULL CHECK ( last_name != '' ), + position TEXT NOT NULL CHECK ( position != '' ), + hire_date DATE NOT NULL, + sex SEX NOT NULL, + salary NUMERIC(12, 2) CHECK ( salary >= 0 ) +); + +CREATE TABLE table_sales_orders +( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + client_id INT, + employee_id INT NOT NULL, + product_id INT NOT NULL, + selling_price NUMERIC(12, 2) NOT NULL CHECK ( selling_price >= 0 ), + quantity INT NOT NULL CHECK ( quantity > 0 ), + sale_date TIMESTAMPTZ NOT NULL DEFAULT NOW(), + + FOREIGN KEY (client_id) REFERENCES table_clients (id), + FOREIGN KEY (employee_id) REFERENCES table_employees (id), + FOREIGN KEY (product_id) REFERENCES table_products (id) +); + +CREATE TABLE table_client_emails +( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + client_id INT NOT NULL, + email TEXT NOT NULL CHECK ( email != '' ), + email_type email_domain_enum NOT NULL, + + FOREIGN KEY (client_id) REFERENCES table_clients (id) +); + +CREATE TABLE table_client_phones +( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + client_id INT NOT NULL, + phone_number TEXT NOT NULL CHECK ( phone_number != '' ), + + FOREIGN KEY (client_id) REFERENCES table_clients (id) +); + + + +CREATE OR REPLACE FUNCTION trg_decrease_stock() + RETURNS TRIGGER AS +$$ +BEGIN + + IF (SELECT stock_quantity + FROM table_products + WHERE id = NEW.product_id) < NEW.quantity THEN + RAISE EXCEPTION 'Not enought stock for products %', NEW.product_id; + END IF; + + UPDATE table_products + SET stock_quantity = stock_quantity - NEW.quantity + WHERE id = NEW.product_id; + + RETURN NEW; + +END +$$ + LANGUAGE plpgsql; + +CREATE TRIGGER before_insert_sales_orders_decrease_stock + BEFORE INSERT + ON table_sales_orders + FOR EACH ROW +EXECUTE FUNCTION trg_decrease_stock(); + +-- Производители +INSERT INTO table_manufacturers (name_manufacturer, country) +VALUES ('Nike', 'USA'), + ('Adidas', 'Germany'), + ('Puma', 'Germany'), + ('Reebok', 'USA'), + ('Decathlon', 'France'); + +-- Товары +INSERT INTO table_products (manufacturer_id, product_name, product_type, stock_quantity, cost_price, selling_price) +VALUES (1, 'Nike Air Max 90', 'Footwear', 50, 2500.00, 5999.00), + (1, 'Nike Dri-FIT T-Shirt', 'Clothing', 120, 800.00, 1999.00), + (2, 'Adidas Ultraboost 23', 'Footwear', 35, 3000.00, 7499.00), + (2, 'Adidas Running Shorts', 'Clothing', 80, 600.00, 1499.00), + (3, 'Puma RS-X', 'Footwear', 45, 2200.00, 4999.00), + (4, 'Reebok Classics', 'Footwear', 25, 1800.00, 3999.00), + (5, 'Decathlon Yoga Mat', 'Equipment', 100, 300.00, 799.00), + (5, 'Decathlon Water Bottle', 'Equipment', 200, 150.00, 399.00); + +-- Клиенты +INSERT INTO table_clients (first_name, patronymic, last_name, sex, discount_percent, is_subscribed_newsletter) +VALUES ('Иван', 'Сергеевич', 'Петров', 'M', 5.00, true), + ('Мария', 'Ивановна', 'Сидорова', 'F', 10.00, true), + ('Алексей', 'Владимирович', 'Иванов', 'M', 0.00, false), + ('Екатерина', 'Александровна', 'Смирнова', 'F', 7.50, true), + ('Павел', NULL, 'Козлов', 'M', 0.00, false); + +-- Email клиентов +INSERT INTO table_client_emails (client_id, email, email_type) +VALUES (1, 'ivan.petrov@gmail.com', 'gmail.com'), + (1, 'ivan.petrov@yandex.ru', 'yandex.ru'), + (2, 'maria.sidorova@mail.ru', 'mail.ru'), + (3, 'alex.ivanov@gmail.com', 'gmail.com'), + (4, 'katerina.smirnova@outlook.com', 'outlook.com'), + (5, 'pavel.kozlov@yandex.ru', 'yandex.ru'); + +-- Телефоны клиентов +INSERT INTO table_client_phones (client_id, phone_number) +VALUES (1, '+7-999-123-45-67'), + (1, '+7-995-987-65-43'), + (2, '+7-996-555-11-22'), + (3, '+7-998-777-88-99'), + (4, '+7-999-444-33-22'), + (5, '+7-995-111-22-33'); + +-- Сотрудники +INSERT INTO table_employees (first_name, patronymic, last_name, position, hire_date, sex, salary) +VALUES ('Игорь', 'Эдуардович', 'Морозов', 'Sales Manager', '2023-01-15', 'M', 45000.00), + ('Анна', 'Петровна', 'Волкова', 'Sales Associate', '2023-06-01', 'F', 30000.00), + ('Дмитрий', 'Сергеевич', 'Соколов', 'Sales Associate', '2024-02-10', 'M', 30000.00), + ('Светлана', 'Викторовна', 'Новикова', 'Store Manager', '2022-11-20', 'F', 55000.00), + ('Юрий', 'Львович', 'Лебедев', 'Warehouse Manager', '2023-03-05', 'M', 40000.00); + +-- Продажи +INSERT INTO table_sales_orders (client_id, employee_id, product_id, selling_price, quantity, sale_date) +VALUES (1, 2, 1, 5999.00, 1, '2025-12-01 10:30:00'), + (2, 3, 4, 1499.00, 2, '2025-12-02 14:15:00'), + (3, 2, 7, 799.00, 3, '2025-12-03 09:45:00'), + (4, 1, 3, 7499.00, 1, '2025-12-04 16:20:00'), + (1, 3, 8, 399.00, 5, '2025-12-05 11:00:00'), + (NULL, 2, 2, 1999.00, 1, '2025-12-06 13:30:00'), -- покупатель без регистрации + (2, 1, 5, 4999.00, 1, '2025-12-07 15:45:00'); + + +CREATE OR REPLACE VIEW v_employee_sales_stats AS +SELECT + e.id, + e.first_name || ' ' || e.last_name AS employee_name, + e.position, + COUNT(so.id) AS total_sales, + SUM(so.quantity) AS total_items_sold, + SUM(so.quantity * so.selling_price) AS total_revenue, + ROUND(AVG(so.quantity * so.selling_price), 2) AS avg_sale_amount +FROM table_employees e + LEFT JOIN table_sales_orders so ON e.id = so.employee_id +GROUP BY e.id, e.first_name, e.last_name, e.position +ORDER BY total_revenue DESC; + + +SELECT * FROM v_employee_sales_stats; \ No newline at end of file From d038e51c35cd71bbd5ffdd8374fd84de36dbb98e Mon Sep 17 00:00:00 2001 From: KomariK Date: Mon, 8 Dec 2025 08:21:23 +0300 Subject: [PATCH 4/4] Add files via upload