From 06ed908beb82044f5af63c96d1f3d901f0a57e2f Mon Sep 17 00:00:00 2001 From: PerevoznikovLeonid Date: Mon, 24 Nov 2025 11:59:13 +0300 Subject: [PATCH 1/6] Add files via upload --- sports_store.sql | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 sports_store.sql diff --git a/sports_store.sql b/sports_store.sql new file mode 100644 index 0000000..0dd3391 --- /dev/null +++ b/sports_store.sql @@ -0,0 +1,72 @@ +CREATE TABLE table_product_types ( + id SERIAL NOT NULL PRIMARY KEY, + name TEXT NOT NULL CHECK ( name != '' ), + description TEXT NOT NULL CHECK ( name != '' ) +); + +CREATE TABLE table_products ( + id SERIAL NOT NULL PRIMARY KEY, + name TEXT NOT NULL CHECK ( name != '' ), + type_id INT NOT NULL, + amount_in_stock INT NOT NULL CHECK ( amount_in_stock >= 0 ), + cost_price NUMERIC NOT NULL CHECK ( cost_price >= 0.0 ), + manufacturer TEXT NOT NULL CHECK ( name != '' ), + price NUMERIC NOT NULL CHECK ( price >= 0.0 ), + FOREIGN KEY (type_id) REFERENCES table_product_types(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); + +CREATE TABLE table_employees ( + id SERIAL NOT NULL PRIMARY KEY, + first_name TEXT NOT NULL CHECK ( first_name != '' ), + last_name TEXT NOT NULL CHECK ( last_name != '' ), + patronymic TEXT CHECK ( patronymic != '' ), + job TEXT NOT NULL CHECK ( job != '' ), + hiring_date DATE NOT NULL, + gender CHAR NOT NULL CHECK ( gender = 'M' OR gender = 'F' ), + salary NUMERIC NOT NULL CHECK ( salary >= 0.0 ) +); + +CREATE TABLE table_clients ( + id SERIAL NOT NULL PRIMARY KEY, + first_name TEXT NOT NULL CHECK ( first_name != '' ) DEFAULT 'UNREGISTERED', + last_name TEXT NOT NULL CHECK ( last_name != '' ) DEFAULT 'UNREGISTERED', + patronymic TEXT CHECK ( patronymic != '' ), + email TEXT NOT NULL CHECK ( email LIKE '%@%' ) DEFAULT 'UNREGISTERED', + phoneNumber TEXT NOT NULL CHECK ( phoneNumber != '' ) DEFAULT 'UNREGISTERED', + gender CHAR CHECK ( gender = 'M' OR gender = 'F' ), + discount_percent NUMERIC(3, 2) NOT NULL CHECK ( discount_percent >= 0.00 ) DEFAULT 0.00, + is_subscribed_to_mailing_list BOOLEAN NOT NULL DEFAULT FALSE +); + +CREATE TABLE table_sales ( + id SERIAL NOT NULL PRIMARY KEY, + product_id INT NOT NULL, + amount_sold INT NOT NULL CHECK ( amount_sold >= 0 ), + total_price NUMERIC NOT NULL CHECK ( total_price >= 0.0 ), + date DATE NOT NULL, + employee_id INT NOT NULL, + client_id INT NOT NULL, + FOREIGN KEY (product_id) REFERENCES table_products(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (employee_id) REFERENCES table_employees(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (client_id) REFERENCES table_clients(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); + +CREATE TABLE table_order_histories ( + id SERIAL NOT NULL PRIMARY KEY, + client_id INT NOT NULL, + sale_id INT NOT NULL, + FOREIGN KEY (client_id) REFERENCES table_clients(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (sale_id) REFERENCES table_sales(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); \ No newline at end of file From ab46a4990e79c6d09c87a689bf11e9fbf7550651 Mon Sep 17 00:00:00 2001 From: PerevoznikovLeonid Date: Tue, 25 Nov 2025 11:56:45 +0300 Subject: [PATCH 2/6] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sports_store.sql | 87 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/sports_store.sql b/sports_store.sql index 0dd3391..5d27de5 100644 --- a/sports_store.sql +++ b/sports_store.sql @@ -1,72 +1,103 @@ +CREATE TYPE person_gender AS ENUM ('M', 'F'); + CREATE TABLE table_product_types ( id SERIAL NOT NULL PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), description TEXT NOT NULL CHECK ( name != '' ) ); +CREATE TABLE table_manufacturers ( + id SERIAL NOT NULL PRIMARY KEY, + name TEXT NOT NULL CHECK ( name != '' ), + description TEXT NOT NULL CHECK ( name != '' ) +); + CREATE TABLE table_products ( id SERIAL NOT NULL PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), type_id INT NOT NULL, amount_in_stock INT NOT NULL CHECK ( amount_in_stock >= 0 ), cost_price NUMERIC NOT NULL CHECK ( cost_price >= 0.0 ), - manufacturer TEXT NOT NULL CHECK ( name != '' ), + manufacturer_id INT NOT NULL, price NUMERIC NOT NULL CHECK ( price >= 0.0 ), + measurement_unit TEXT CHECK ( name != '' ), + measurement_value NUMERIC CHECK ( measurement_value >= 0.0 ), FOREIGN KEY (type_id) REFERENCES table_product_types(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (manufacturer_id) REFERENCES table_manufacturers(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); -CREATE TABLE table_employees ( +CREATE TABLE table_persons ( id SERIAL NOT NULL PRIMARY KEY, first_name TEXT NOT NULL CHECK ( first_name != '' ), last_name TEXT NOT NULL CHECK ( last_name != '' ), patronymic TEXT CHECK ( patronymic != '' ), - job TEXT NOT NULL CHECK ( job != '' ), + gender person_gender NOT NULL CHECK ( gender != '' ), + email TEXT NOT NULL CHECK ( email LIKE '%@%' ), + phoneNumber TEXT NOT NULL CHECK ( phoneNumber != '' ) +); + +CREATE TABLE table_employees ( + id SERIAL NOT NULL PRIMARY KEY, + person_id INT NOT NULL, + position TEXT NOT NULL CHECK ( position != '' ), hiring_date DATE NOT NULL, - gender CHAR NOT NULL CHECK ( gender = 'M' OR gender = 'F' ), - salary NUMERIC NOT NULL CHECK ( salary >= 0.0 ) + salary NUMERIC NOT NULL CHECK ( salary >= 0.0 ), + FOREIGN KEY (person_id) REFERENCES table_persons(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION ); CREATE TABLE table_clients ( id SERIAL NOT NULL PRIMARY KEY, - first_name TEXT NOT NULL CHECK ( first_name != '' ) DEFAULT 'UNREGISTERED', - last_name TEXT NOT NULL CHECK ( last_name != '' ) DEFAULT 'UNREGISTERED', - patronymic TEXT CHECK ( patronymic != '' ), - email TEXT NOT NULL CHECK ( email LIKE '%@%' ) DEFAULT 'UNREGISTERED', - phoneNumber TEXT NOT NULL CHECK ( phoneNumber != '' ) DEFAULT 'UNREGISTERED', - gender CHAR CHECK ( gender = 'M' OR gender = 'F' ), - discount_percent NUMERIC(3, 2) NOT NULL CHECK ( discount_percent >= 0.00 ) DEFAULT 0.00, - is_subscribed_to_mailing_list BOOLEAN NOT NULL DEFAULT FALSE + person_id INT NOT NULL, + discount_percent NUMERIC(3, 2) NOT NULL CHECK ( discount_percent < 1.00 AND discount_percent >= 0.00) DEFAULT 0.00, + is_subscribed_to_mailing_list BOOLEAN NOT NULL DEFAULT FALSE, + FOREIGN KEY (person_id) REFERENCES table_persons(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION ); -CREATE TABLE table_sales ( +CREATE TABLE table_orders ( id SERIAL NOT NULL PRIMARY KEY, - product_id INT NOT NULL, - amount_sold INT NOT NULL CHECK ( amount_sold >= 0 ), - total_price NUMERIC NOT NULL CHECK ( total_price >= 0.0 ), + items_price NUMERIC NOT NULL CHECK ( items_price >= 0.0 ), + items_amount INT NOT NULL CHECK ( items_amount >= 0 ), date DATE NOT NULL, - employee_id INT NOT NULL, - client_id INT NOT NULL, - FOREIGN KEY (product_id) REFERENCES table_products(id) + is_payed BOOLEAN NOT NULL DEFAULT FALSE, + is_client_registered BOOLEAN NOT NULL DEFAULT FALSE, + client_id INT, + FOREIGN KEY (client_id) REFERENCES table_clients(id) ON DELETE NO ACTION - ON UPDATE NO ACTION, - FOREIGN KEY (employee_id) REFERENCES table_employees(id) + ON UPDATE NO ACTION +); + +CREATE TABLE table_order_items ( + id SERIAL NOT NULL PRIMARY KEY, + order_id INT NOT NULL, + product_id INT NOT NULL, + amount INT NOT NULL CHECK ( amount >= 0 ), + FOREIGN KEY (order_id) REFERENCES table_orders(id) ON DELETE NO ACTION ON UPDATE NO ACTION, - FOREIGN KEY (client_id) REFERENCES table_clients(id) + FOREIGN KEY (product_id) REFERENCES table_products(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); -CREATE TABLE table_order_histories ( +CREATE TABLE table_sales ( id SERIAL NOT NULL PRIMARY KEY, - client_id INT NOT NULL, - sale_id INT NOT NULL, - FOREIGN KEY (client_id) REFERENCES table_clients(id) + order_id INT NOT NULL, + total_price NUMERIC NOT NULL CHECK ( total_price >= 0.0 ), + payment_type TEXT NOT NULL CHECK ( payment_type != '' ), + employee_id INT NOT NULL, + date DATE NOT NULL, + FOREIGN KEY (order_id) REFERENCES table_orders(id) ON DELETE NO ACTION ON UPDATE NO ACTION, - FOREIGN KEY (sale_id) REFERENCES table_sales(id) + FOREIGN KEY (employee_id) REFERENCES table_employees(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); \ No newline at end of file From c380f00346024b21353e54d99a66f1a96ad68a2e Mon Sep 17 00:00:00 2001 From: PerevoznikovLeonid Date: Mon, 1 Dec 2025 11:25:37 +0300 Subject: [PATCH 3/6] Add files via upload --- sports_store.sql | 77 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/sports_store.sql b/sports_store.sql index 5d27de5..e849db5 100644 --- a/sports_store.sql +++ b/sports_store.sql @@ -1,15 +1,47 @@ CREATE TYPE person_gender AS ENUM ('M', 'F'); -CREATE TABLE table_product_types ( +CREATE TABLE table_persons ( id SERIAL NOT NULL PRIMARY KEY, - name TEXT NOT NULL CHECK ( name != '' ), - description TEXT NOT NULL CHECK ( name != '' ) + first_name TEXT NOT NULL CHECK ( first_name != '' ), + last_name TEXT NOT NULL CHECK ( last_name != '' ), + patronymic TEXT CHECK ( patronymic != '' ), + gender person_gender NOT NULL CHECK ( gender != '' ), + date_of_birth DATE +); + +CREATE TABLE table_emails ( + id SERIAL NOT NULL PRIMARY KEY, + person_id INT NOT NULL, + email TEXT NOT NULL CHECK ( email LIKE '%@%' ), + FOREIGN KEY (person_id) REFERENCES table_phone_numbers(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); + +CREATE TABLE table_phone_numbers ( + id SERIAL NOT NULL PRIMARY KEY, + person_id INT NOT NULL, + phone_number TEXT NOT NULL CHECK ( phone_number != '' ), + FOREIGN KEY (person_id) REFERENCES table_phone_numbers(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION ); CREATE TABLE table_manufacturers ( id SERIAL NOT NULL PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), - description TEXT NOT NULL CHECK ( name != '' ) + address TEXT CHECK ( address != '' ), + contact_person_id INT NOT NULL, + description TEXT CHECK ( name != '' ), + FOREIGN KEY (contact_person_id) REFERENCES table_persons(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); + +CREATE TABLE table_product_types ( + id SERIAL NOT NULL PRIMARY KEY, + name TEXT NOT NULL CHECK ( name != '' ), + description TEXT CHECK ( name != '' ) ); CREATE TABLE table_products ( @@ -30,23 +62,44 @@ CREATE TABLE table_products ( ON UPDATE NO ACTION ); -CREATE TABLE table_persons ( +CREATE TABLE table_positions ( id SERIAL NOT NULL PRIMARY KEY, - first_name TEXT NOT NULL CHECK ( first_name != '' ), - last_name TEXT NOT NULL CHECK ( last_name != '' ), - patronymic TEXT CHECK ( patronymic != '' ), - gender person_gender NOT NULL CHECK ( gender != '' ), - email TEXT NOT NULL CHECK ( email LIKE '%@%' ), - phoneNumber TEXT NOT NULL CHECK ( phoneNumber != '' ) + name TEXT NOT NULL CHECK ( name != '' ), + level TEXT NOT NULL CHECK ( level != '' ), + average_salary NUMERIC NOT NULL CHECK ( average_salary >= 0.0 ), + requirements TEXT NOT NULL CHECK ( requirements != '' ), + tasks TEXT NOT NULL CHECK ( tasks != '' ), + is_hiring BOOLEAN NOT NULL DEFAULT FALSE ); CREATE TABLE table_employees ( id SERIAL NOT NULL PRIMARY KEY, person_id INT NOT NULL, - position TEXT NOT NULL CHECK ( position != '' ), + position_id INT NOT NULL, hiring_date DATE NOT NULL, salary NUMERIC NOT NULL CHECK ( salary >= 0.0 ), FOREIGN KEY (person_id) REFERENCES table_persons(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (position_id) REFERENCES table_positions(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); + +CREATE TABLE table_price_history ( + id SERIAL NOT NULL PRIMARY KEY, + product_id INT NOT NULL, + employee_id INT NOT NULL, + old_cost_price NUMERIC NOT NULL CHECK ( old_cost_price >= 0.0 ), + new_cost_price NUMERIC NOT NULL CHECK ( new_cost_price >= 0.0 ), + old_price NUMERIC NOT NULL CHECK ( old_price >= 0.0 ), + new_price NUMERIC NOT NULL CHECK ( new_price >= 0.0 ), + change_date DATE NOT NULL, + change_reason TEXT CHECK ( change_reason != '' ), + FOREIGN KEY (product_id) REFERENCES table_products(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (employee_id) REFERENCES table_employees(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); From ef28840414d13ac6ef468c5d6f17cdbf640f6ed6 Mon Sep 17 00:00:00 2001 From: PerevoznikovLeonid Date: Tue, 2 Dec 2025 15:18:16 +0300 Subject: [PATCH 4/6] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=82=D1=80=D0=B8=D0=B3=D0=B3=D0=B5=D1=80=20(=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=BA=D0=BE=D0=BD=D1=87=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sports_store.sql | 64 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/sports_store.sql b/sports_store.sql index e849db5..1549404 100644 --- a/sports_store.sql +++ b/sports_store.sql @@ -54,6 +54,7 @@ CREATE TABLE table_products ( price NUMERIC NOT NULL CHECK ( price >= 0.0 ), measurement_unit TEXT CHECK ( name != '' ), measurement_value NUMERIC CHECK ( measurement_value >= 0.0 ), + is_archived BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (type_id) REFERENCES table_product_types(id) ON DELETE NO ACTION ON UPDATE NO ACTION, @@ -62,6 +63,16 @@ CREATE TABLE table_products ( ON UPDATE NO ACTION ); +-- Товар должен помещаться в архив, когда его количество становится 0 +CREATE TABLE table_archived_products_log ( + id SERIAL NOT NULL PRIMARY KEY, + product_id INT NOT NULL, + change_date DATE NOT NULL, + FOREIGN KEY (product_id) REFERENCES table_products(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); + CREATE TABLE table_positions ( id SERIAL NOT NULL PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), @@ -78,6 +89,7 @@ CREATE TABLE table_employees ( position_id INT NOT NULL, hiring_date DATE NOT NULL, salary NUMERIC NOT NULL CHECK ( salary >= 0.0 ), + is_deleted BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (person_id) REFERENCES table_persons(id) ON DELETE NO ACTION ON UPDATE NO ACTION, @@ -86,14 +98,30 @@ CREATE TABLE table_employees ( ON UPDATE NO ACTION ); +CREATE TABLE employee_history ( + id SERIAL NOT NULL PRIMARY KEY, + employee_id INT NOT NULL, + supervisor_id INT NOT NULL, + position_id INT NOT NULL, + change_date DATE NOT NULL, + change_reason TEXT CHECK ( change_reason != '' ), + FOREIGN KEY (employee_id) REFERENCES table_employees(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (supervisor_id) REFERENCES table_employees(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (position_id) REFERENCES table_positions(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION +); + CREATE TABLE table_price_history ( id SERIAL NOT NULL PRIMARY KEY, product_id INT NOT NULL, employee_id INT NOT NULL, - old_cost_price NUMERIC NOT NULL CHECK ( old_cost_price >= 0.0 ), - new_cost_price NUMERIC NOT NULL CHECK ( new_cost_price >= 0.0 ), - old_price NUMERIC NOT NULL CHECK ( old_price >= 0.0 ), - new_price NUMERIC NOT NULL CHECK ( new_price >= 0.0 ), + cost_price NUMERIC NOT NULL CHECK ( cost_price >= 0.0 ), + price NUMERIC NOT NULL CHECK ( price >= 0.0 ), change_date DATE NOT NULL, change_reason TEXT CHECK ( change_reason != '' ), FOREIGN KEY (product_id) REFERENCES table_products(id) @@ -109,6 +137,7 @@ CREATE TABLE table_clients ( person_id INT NOT NULL, discount_percent NUMERIC(3, 2) NOT NULL CHECK ( discount_percent < 1.00 AND discount_percent >= 0.00) DEFAULT 0.00, is_subscribed_to_mailing_list BOOLEAN NOT NULL DEFAULT FALSE, + is_deleted BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (person_id) REFERENCES table_persons(id) ON DELETE NO ACTION ON UPDATE NO ACTION @@ -153,4 +182,29 @@ CREATE TABLE table_sales ( FOREIGN KEY (employee_id) REFERENCES table_employees(id) ON DELETE NO ACTION ON UPDATE NO ACTION -); \ No newline at end of file +); + +CREATE FUNCTION function_archive_product() + RETURNS TRIGGER + LANGUAGE plpgsql +AS +$$ +BEGIN + IF (tg_table_name == 'table_products') THEN + IF (NEW.amount_in_stock = 0 AND NEW.is_archived = FALSE) THEN + NEW.is_archived = TRUE; + INSERT INTO table_archived_products_log(product_id, change_date) + VALUES (NEW.id, current_date); + ELSEIF (NEW.amount_in_stock > 0 AND NEW.is_archived = TRUE) THEN + NEW.is_archived = FALSE; + END IF; + END IF; +END; +$$; + + +CREATE TRIGGER trigger_archive_product + BEFORE UPDATE + ON table_products + FOR EACH ROW + EXECUTE FUNCTION function_archive_product(); \ No newline at end of file From 189ca1a2bcb600636a3f5995f527ae58c99a6f1d Mon Sep 17 00:00:00 2001 From: PerevoznikovLeonid Date: Fri, 5 Dec 2025 16:14:11 +0300 Subject: [PATCH 5/6] =?UTF-8?q?=D0=94=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0=D0=BD?= =?UTF-8?q?=20=D1=82=D1=80=D0=B8=D0=B3=D0=B3=D0=B5=D1=80=20=D0=B8=20view?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sports_store.sql | 107 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/sports_store.sql b/sports_store.sql index 1549404..a444e0d 100644 --- a/sports_store.sql +++ b/sports_store.sql @@ -1,16 +1,17 @@ CREATE TYPE person_gender AS ENUM ('M', 'F'); CREATE TABLE table_persons ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, first_name TEXT NOT NULL CHECK ( first_name != '' ), last_name TEXT NOT NULL CHECK ( last_name != '' ), patronymic TEXT CHECK ( patronymic != '' ), gender person_gender NOT NULL CHECK ( gender != '' ), - date_of_birth DATE + date_of_birth DATE, + is_deleted BOOLEAN NOT NULL DEFAULT FALSE ); CREATE TABLE table_emails ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, person_id INT NOT NULL, email TEXT NOT NULL CHECK ( email LIKE '%@%' ), FOREIGN KEY (person_id) REFERENCES table_phone_numbers(id) @@ -19,7 +20,7 @@ CREATE TABLE table_emails ( ); CREATE TABLE table_phone_numbers ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, person_id INT NOT NULL, phone_number TEXT NOT NULL CHECK ( phone_number != '' ), FOREIGN KEY (person_id) REFERENCES table_phone_numbers(id) @@ -28,7 +29,7 @@ CREATE TABLE table_phone_numbers ( ); CREATE TABLE table_manufacturers ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), address TEXT CHECK ( address != '' ), contact_person_id INT NOT NULL, @@ -39,13 +40,13 @@ CREATE TABLE table_manufacturers ( ); CREATE TABLE table_product_types ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), description TEXT CHECK ( name != '' ) ); CREATE TABLE table_products ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), type_id INT NOT NULL, amount_in_stock INT NOT NULL CHECK ( amount_in_stock >= 0 ), @@ -65,7 +66,7 @@ CREATE TABLE table_products ( -- Товар должен помещаться в архив, когда его количество становится 0 CREATE TABLE table_archived_products_log ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, product_id INT NOT NULL, change_date DATE NOT NULL, FOREIGN KEY (product_id) REFERENCES table_products(id) @@ -74,7 +75,7 @@ CREATE TABLE table_archived_products_log ( ); CREATE TABLE table_positions ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name TEXT NOT NULL CHECK ( name != '' ), level TEXT NOT NULL CHECK ( level != '' ), average_salary NUMERIC NOT NULL CHECK ( average_salary >= 0.0 ), @@ -84,7 +85,7 @@ CREATE TABLE table_positions ( ); CREATE TABLE table_employees ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, person_id INT NOT NULL, position_id INT NOT NULL, hiring_date DATE NOT NULL, @@ -98,11 +99,12 @@ CREATE TABLE table_employees ( ON UPDATE NO ACTION ); -CREATE TABLE employee_history ( - id SERIAL NOT NULL PRIMARY KEY, +CREATE TABLE table_employee_history ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, employee_id INT NOT NULL, supervisor_id INT NOT NULL, position_id INT NOT NULL, + salary NUMERIC NOT NULL CHECK ( salary >= 0.0 ), change_date DATE NOT NULL, change_reason TEXT CHECK ( change_reason != '' ), FOREIGN KEY (employee_id) REFERENCES table_employees(id) @@ -117,7 +119,7 @@ CREATE TABLE employee_history ( ); CREATE TABLE table_price_history ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, product_id INT NOT NULL, employee_id INT NOT NULL, cost_price NUMERIC NOT NULL CHECK ( cost_price >= 0.0 ), @@ -133,7 +135,7 @@ CREATE TABLE table_price_history ( ); CREATE TABLE table_clients ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, person_id INT NOT NULL, discount_percent NUMERIC(3, 2) NOT NULL CHECK ( discount_percent < 1.00 AND discount_percent >= 0.00) DEFAULT 0.00, is_subscribed_to_mailing_list BOOLEAN NOT NULL DEFAULT FALSE, @@ -144,7 +146,7 @@ CREATE TABLE table_clients ( ); CREATE TABLE table_orders ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, items_price NUMERIC NOT NULL CHECK ( items_price >= 0.0 ), items_amount INT NOT NULL CHECK ( items_amount >= 0 ), date DATE NOT NULL, @@ -157,7 +159,7 @@ CREATE TABLE table_orders ( ); CREATE TABLE table_order_items ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, order_id INT NOT NULL, product_id INT NOT NULL, amount INT NOT NULL CHECK ( amount >= 0 ), @@ -170,7 +172,7 @@ CREATE TABLE table_order_items ( ); CREATE TABLE table_sales ( - id SERIAL NOT NULL PRIMARY KEY, + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, order_id INT NOT NULL, total_price NUMERIC NOT NULL CHECK ( total_price >= 0.0 ), payment_type TEXT NOT NULL CHECK ( payment_type != '' ), @@ -185,26 +187,79 @@ CREATE TABLE table_sales ( ); CREATE FUNCTION function_archive_product() - RETURNS TRIGGER - LANGUAGE plpgsql -AS + RETURNS TRIGGER AS $$ BEGIN - IF (tg_table_name == 'table_products') THEN + IF (tg_table_name == 'table_products' + AND tg_op = 'UPDATE' + AND NEW.amount_in_stock != OLD.amount_in_stock) THEN + IF (NEW.amount_in_stock = 0 AND NEW.is_archived = FALSE) THEN + NEW.is_archived = TRUE; + INSERT INTO table_archived_products_log(product_id, change_date) + VALUES (OLD.id, CURRENT_DATE); + ELSIF (NEW.amount_in_stock > 0 AND NEW.is_archived = TRUE) THEN + NEW.is_archived = FALSE; + END IF; + ELSIF (tg_table_name = 'table_products' AND tg_op = 'INSERT') THEN IF (NEW.amount_in_stock = 0 AND NEW.is_archived = FALSE) THEN NEW.is_archived = TRUE; INSERT INTO table_archived_products_log(product_id, change_date) - VALUES (NEW.id, current_date); - ELSEIF (NEW.amount_in_stock > 0 AND NEW.is_archived = TRUE) THEN + VALUES (NEW.id, CURRENT_DATE); + ELSIF (NEW.amount_in_stock > 0 AND NEW.is_archived = TRUE) THEN NEW.is_archived = FALSE; END IF; END IF; + RETURN NULL; END; -$$; - +$$ +LANGUAGE plpgsql; CREATE TRIGGER trigger_archive_product BEFORE UPDATE ON table_products FOR EACH ROW - EXECUTE FUNCTION function_archive_product(); \ No newline at end of file + EXECUTE FUNCTION function_archive_product(); + +CREATE VIEW view_product_price_history AS + SELECT table_products.id AS product_id, + table_products.name AS name, + table_product_types.name AS type, + table_product_types.description AS description, + table_products.amount_in_stock AS amount_in_stock, + table_manufacturers.name AS manufacturer, + table_persons.id AS person_id, + table_persons.first_name AS price_change_employee_first_name, + table_persons.last_name AS price_change_employee_last_name, + table_persons.patronymic AS price_change_employee_patronymic, + table_price_history.cost_price AS cost_price, + table_price_history.price AS selling_price, + table_price_history.change_date AS change_date, + table_price_history.change_reason AS change_reason, + table_products.measurement_unit AS measurement_unit, + table_products.measurement_value AS measurement_value, + table_products.is_archived AS is_archived + FROM table_price_history + JOIN table_products ON table_price_history.product_id = table_products.id + JOIN table_product_types ON table_products.type_id = table_product_types.id + JOIN table_manufacturers ON table_products.manufacturer_id = table_manufacturers.id + JOIN table_employees ON table_price_history.employee_id = table_employees.id + JOIN table_persons ON table_employees.person_id = table_persons.id; + +CREATE VIEW view_employee_history AS + SELECT table_employees.id AS employee_id, + table_persons.id AS person_id, + table_persons.first_name AS first_name, + table_persons.last_name AS last_name, + table_persons.patronymic AS patronymic, + table_persons.gender AS gender, + table_persons.date_of_birth AS date_of_birth, + table_employee_history.supervisor_id as supervisor_id, + table_positions.name AS position, + table_employee_history.salary as salary, + table_employee_history.change_date as change_date, + table_employee_history.change_reason as change_reason + FROM table_employee_history + JOIN table_employees ON table_employee_history.employee_id = table_employees.id + JOIN table_persons ON table_employees.person_id = table_persons.id + JOIN table_positions ON table_employee_history.position_id = table_positions.id + From 23546500b274882884215041cf74364b35efe289 Mon Sep 17 00:00:00 2001 From: PerevoznikovLeonid Date: Mon, 8 Dec 2025 11:45:11 +0300 Subject: [PATCH 6/6] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D1=80=D0=B8=D0=B3=D0=B3=D0=B5=D1=80=D1=8B?= =?UTF-8?q?=20=D0=B8=D1=81=D1=82=D0=BE=D1=80=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sports_store.sql | 110 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 4 deletions(-) diff --git a/sports_store.sql b/sports_store.sql index a444e0d..249cc17 100644 --- a/sports_store.sql +++ b/sports_store.sql @@ -14,7 +14,7 @@ CREATE TABLE table_emails ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, person_id INT NOT NULL, email TEXT NOT NULL CHECK ( email LIKE '%@%' ), - FOREIGN KEY (person_id) REFERENCES table_phone_numbers(id) + FOREIGN KEY (person_id) REFERENCES table_persons(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); @@ -23,7 +23,7 @@ CREATE TABLE table_phone_numbers ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, person_id INT NOT NULL, phone_number TEXT NOT NULL CHECK ( phone_number != '' ), - FOREIGN KEY (person_id) REFERENCES table_phone_numbers(id) + FOREIGN KEY (person_id) REFERENCES table_persons(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); @@ -53,6 +53,8 @@ CREATE TABLE table_products ( cost_price NUMERIC NOT NULL CHECK ( cost_price >= 0.0 ), manufacturer_id INT NOT NULL, price NUMERIC NOT NULL CHECK ( price >= 0.0 ), + price_reason TEXT CHECK ( price_reason != '' ), + price_set_employee_id INT NOT NULL, measurement_unit TEXT CHECK ( name != '' ), measurement_value NUMERIC CHECK ( measurement_value >= 0.0 ), is_archived BOOLEAN NOT NULL DEFAULT FALSE, @@ -60,6 +62,9 @@ CREATE TABLE table_products ( ON DELETE NO ACTION ON UPDATE NO ACTION, FOREIGN KEY (manufacturer_id) REFERENCES table_manufacturers(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (price_set_employee_id) REFERENCES table_employees(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); @@ -90,11 +95,16 @@ CREATE TABLE table_employees ( position_id INT NOT NULL, hiring_date DATE NOT NULL, salary NUMERIC NOT NULL CHECK ( salary >= 0.0 ), + supervisor_id INT NOT NULL, + position_reason TEXT CHECK ( position_reason != '' ), is_deleted BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (person_id) REFERENCES table_persons(id) ON DELETE NO ACTION ON UPDATE NO ACTION, FOREIGN KEY (position_id) REFERENCES table_positions(id) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + FOREIGN KEY (supervisor_id) REFERENCES table_employees(id) ON DELETE NO ACTION ON UPDATE NO ACTION ); @@ -196,7 +206,7 @@ BEGIN IF (NEW.amount_in_stock = 0 AND NEW.is_archived = FALSE) THEN NEW.is_archived = TRUE; INSERT INTO table_archived_products_log(product_id, change_date) - VALUES (OLD.id, CURRENT_DATE); + VALUES (NEW.id, CURRENT_DATE); ELSIF (NEW.amount_in_stock > 0 AND NEW.is_archived = TRUE) THEN NEW.is_archived = FALSE; END IF; @@ -215,11 +225,103 @@ $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_archive_product - BEFORE UPDATE + BEFORE UPDATE OR INSERT ON table_products FOR EACH ROW EXECUTE FUNCTION function_archive_product(); +CREATE FUNCTION function_log_price_history() +RETURNS TRIGGER AS +$$ +BEGIN + IF (tg_table_name == 'table_products' AND tg_op = 'UPDATE') THEN + IF (NEW.price != OLD.price AND NEW.cost_price != OLD.cost_price) THEN + INSERT INTO table_price_history(product_id, employee_id, + cost_price, price, + change_date, change_reason) + VALUES (NEW.id, NEW.price_set_employee_id, + NEW.cost_price, NEW.price, CURRENT_DATE, + NEW.price_reason); + ELSIF (NEW.price != OLD.price) THEN + INSERT INTO table_price_history(product_id, employee_id, + cost_price, price, + change_date, change_reason) + VALUES (NEW.id, NEW.price_set_employee_id, + NEW.cost_price, NEW.price, CURRENT_DATE, + NEW.price_reason); + ELSIF (NEW.cost_price != OLD.cost_price) THEN + INSERT INTO table_price_history(product_id, employee_id, + cost_price, price, + change_date, change_reason) + VALUES (NEW.id, NEW.price_set_employee_id, + NEW.cost_price, NEW.price, CURRENT_DATE, + NEW.price_reason); + END IF; + ELSIF (tg_table_name == 'table_products' AND tg_op = 'INSERT') THEN + INSERT INTO table_price_history(product_id, employee_id, + cost_price, price, + change_date, change_reason) + VALUES (NEW.id, NEW.price_set_employee_id, + NEW.cost_price, NEW.price, CURRENT_DATE, + NEW.price_reason); + END IF; + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; + +CREATE TRIGGER trigger_log_price_history + BEFORE UPDATE OR INSERT + ON table_products + FOR EACH ROW + EXECUTE FUNCTION function_log_price_history(); + +CREATE FUNCTION function_log_employee_history() +RETURNS TRIGGER AS +$$ +BEGIN + IF (tg_table_name == 'table_employees' AND tg_op = 'UPDATE') THEN + IF (NEW.position_id != OLD.position_id AND NEW.salary != OLD.salary) THEN + INSERT INTO table_employee_history(employee_id, supervisor_id, + position_id, salary, + change_date, change_reason) + VALUES (NEW.id, NEW.supervisor_id, + NEW.position_id, NEW.salary, CURRENT_DATE, + NEW.position_reason); + ELSIF (NEW.position_id != OLD.position_id) THEN + INSERT INTO table_employee_history(employee_id, supervisor_id, + position_id, salary, + change_date, change_reason) + VALUES (NEW.id, NEW.supervisor_id, + NEW.position_id, NEW.salary, CURRENT_DATE, + NEW.position_reason); + ELSIF (NEW.salary != OLD.salary) THEN + INSERT INTO table_employee_history(employee_id, supervisor_id, + position_id, salary, + change_date, change_reason) + VALUES (NEW.id, NEW.supervisor_id, + NEW.position_id, NEW.salary, CURRENT_DATE, + NEW.position_reason); + END IF; + ELSIF (tg_table_name == 'table_employees' AND tg_op = 'INSERT') THEN + INSERT INTO table_employee_history(employee_id, supervisor_id, + position_id, salary, + change_date, change_reason) + VALUES (NEW.id, NEW.supervisor_id, + NEW.position_id, NEW.salary, CURRENT_DATE, + NEW.position_reason); + END IF; + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; + +CREATE TRIGGER trigger_log_employee_history + BEFORE UPDATE OR INSERT + ON table_employees + FOR EACH ROW + EXECUTE FUNCTION function_log_employee_history(); + CREATE VIEW view_product_price_history AS SELECT table_products.id AS product_id, table_products.name AS name,