Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
367 changes: 367 additions & 0 deletions sports_store.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,367 @@
CREATE TYPE person_gender AS ENUM ('M', 'F');

CREATE TABLE table_persons (
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,
is_deleted BOOLEAN NOT NULL DEFAULT FALSE
);

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_persons(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

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_persons(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

CREATE TABLE table_manufacturers (
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,
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 INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL CHECK ( name != '' ),
description TEXT CHECK ( name != '' )
);

CREATE TABLE table_products (
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 ),
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,
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,
FOREIGN KEY (price_set_employee_id) REFERENCES table_employees(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

-- Товар должен помещаться в архив, когда его количество становится 0
CREATE TABLE table_archived_products_log (
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)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

CREATE TABLE table_positions (
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 ),
requirements TEXT NOT NULL CHECK ( requirements != '' ),
tasks TEXT NOT NULL CHECK ( tasks != '' ),
is_hiring BOOLEAN NOT NULL DEFAULT FALSE
);

CREATE TABLE table_employees (
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
person_id INT NOT NULL,
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
);

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)
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 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 ),
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)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
FOREIGN KEY (employee_id) REFERENCES table_employees(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

CREATE TABLE table_clients (
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,
is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
FOREIGN KEY (person_id) REFERENCES table_persons(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

CREATE TABLE table_orders (
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,
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
);

CREATE TABLE table_order_items (
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 ),
FOREIGN KEY (order_id) REFERENCES table_orders(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
FOREIGN KEY (product_id) REFERENCES table_products(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

CREATE TABLE table_sales (
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 != '' ),
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 (employee_id) REFERENCES table_employees(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);

CREATE FUNCTION function_archive_product()
RETURNS TRIGGER AS
$$
BEGIN
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 (NEW.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);
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 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,
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