From be4aeb5975f6a22c4602ecc5a9b3ae63f1d2fc69 Mon Sep 17 00:00:00 2001 From: Arity-T Date: Tue, 29 Oct 2024 08:23:11 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=81=D0=B5=20=D0=B1=D0=B0=D0=B7=D1=8B?= =?UTF-8?q?=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B2=20=D0=BE=D0=B4?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D1=80=D0=B5=D0=BF=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + create_tables.sql | 136 ++++++++ fill_db_script/.gitignore | 1 + fill_db_script/.vscode/launch.json | 15 + fill_db_script/competition_stage.csv | 8 + fill_db_script/division.csv | 17 + fill_db_script/judge.csv | 51 +++ fill_db_script/main.py | 43 +++ fill_db_script/organizer.csv | 21 ++ fill_db_script/sportsman.csv | 101 ++++++ fill_db_script/utils.py | 452 +++++++++++++++++++++++++++ function1.sql | 17 + function2.sql | 8 + procedure.sql | 67 ++++ report.tex => report/report.tex | 0 triggers.sql | 107 +++++++ view1.sql | 17 + view2.sql | 16 + view3.sql | 15 + 19 files changed, 1093 insertions(+) create mode 100644 .gitignore create mode 100644 create_tables.sql create mode 100644 fill_db_script/.gitignore create mode 100644 fill_db_script/.vscode/launch.json create mode 100644 fill_db_script/competition_stage.csv create mode 100644 fill_db_script/division.csv create mode 100644 fill_db_script/judge.csv create mode 100644 fill_db_script/main.py create mode 100644 fill_db_script/organizer.csv create mode 100644 fill_db_script/sportsman.csv create mode 100644 fill_db_script/utils.py create mode 100644 function1.sql create mode 100644 function2.sql create mode 100644 procedure.sql rename report.tex => report/report.tex (100%) create mode 100644 triggers.sql create mode 100644 view1.sql create mode 100644 view2.sql create mode 100644 view3.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f7e924 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**/*.pdf \ No newline at end of file diff --git a/create_tables.sql b/create_tables.sql new file mode 100644 index 0000000..7b0b0c7 --- /dev/null +++ b/create_tables.sql @@ -0,0 +1,136 @@ +CREATE TABLE organizer ( + id_organizer SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + logo VARCHAR(1024) +); + +CREATE TABLE judge ( + id_judge SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + surname VARCHAR(100) NOT NULL, + patronymic VARCHAR(100) NOT NULL, + category VARCHAR(100) NOT NULL, + region VARCHAR(100), + federation VARCHAR(100) +); + +CREATE TABLE sportsman ( + id_sportsman SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + surname VARCHAR(100) NOT NULL, + patronymic VARCHAR(100), + gender VARCHAR(10) NOT NULL, + birthday DATE, + region VARCHAR(100), + club VARCHAR(100), + federation VARCHAR(100), + category VARCHAR(100) +); + +CREATE TABLE division ( + id_division SERIAL PRIMARY KEY, + title VARCHAR(100) NOT NULL, + gender VARCHAR(10) NOT NULL, + bow_type VARCHAR(100) NOT NULL, + distance SMALLINT NOT NULL, + msmk SMALLINT NOT NULL, + ms SMALLINT NOT NULL, + kms SMALLINT NOT NULL, + category_1 SMALLINT NOT NULL, + category_2 SMALLINT NOT NULL, + category_3 SMALLINT NOT NULL +); + +CREATE TABLE competition ( + id_competition SERIAL PRIMARY KEY, + title VARCHAR(100) NOT NULL, + address VARCHAR(100), + logo VARCHAR(1024), + start_date DATE, + end_date DATE, + id_organizer INTEGER, + FOREIGN KEY (id_organizer) REFERENCES organizer(id_organizer) +); + +CREATE TABLE division_in_competition ( + id_division_in_competition SERIAL PRIMARY KEY, + id_division INTEGER NOT NULL, + id_competition INTEGER NOT NULL, + FOREIGN KEY (id_division) REFERENCES division(id_division), + FOREIGN KEY (id_competition) REFERENCES competition(id_competition) +); + +CREATE TABLE protocol ( + id_protocol SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + date DATE NOT NULL, + file VARCHAR(1024) NOT NULL, + id_competition INTEGER NOT NULL, + FOREIGN KEY (id_competition) REFERENCES competition(id_competition) +); + +CREATE TABLE participant_request ( + id_participant_request SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + surname VARCHAR(100) NOT NULL, + patronymic VARCHAR(100), + gender VARCHAR(10) NOT NULL, + birthday DATE, + region VARCHAR(100), + club VARCHAR(100), + federation VARCHAR(100), + category VARCHAR(100), + is_registered BOOLEAN NOT NULL, + id_competition INTEGER NOT NULL, + id_sportsman INTEGER NOT NULL, + id_division INTEGER NOT NULL, + FOREIGN KEY (id_competition) REFERENCES competition(id_competition), + FOREIGN KEY (id_sportsman) REFERENCES sportsman(id_sportsman), + FOREIGN KEY (id_division) REFERENCES division(id_division) +); + +CREATE TABLE competition_stage ( + id_competition_stage SERIAL PRIMARY KEY, + title VARCHAR(100) NOT NULL, + count_of_series SMALLINT NOT NULL +); + +CREATE TABLE result_in_stage ( + id_result_in_stage SERIAL PRIMARY KEY, + score SMALLINT NOT NULL, + shield_index SMALLINT NOT NULL, + target_index CHAR(1) NOT NULL, + id_participant_request INTEGER NOT NULL, + id_division INTEGER NOT NULL, + id_competition_stage INTEGER NOT NULL, + FOREIGN KEY (id_participant_request) REFERENCES participant_request(id_participant_request), + FOREIGN KEY (id_division) REFERENCES division(id_division), + FOREIGN KEY (id_competition_stage) REFERENCES competition_stage(id_competition_stage) +); + +CREATE TABLE judge_request ( + id_judge_request SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + surname VARCHAR(100) NOT NULL, + patronymic VARCHAR(100) NOT NULL, + category VARCHAR(100) NOT NULL, + region VARCHAR(100), + federation VARCHAR(100), + is_registered BOOLEAN NOT NULL, + id_competition INTEGER NOT NULL, + id_judge INTEGER NOT NULL, + FOREIGN KEY (id_competition) REFERENCES competition(id_competition), + FOREIGN KEY (id_judge) REFERENCES judge(id_judge) +); + +CREATE TABLE shot_series ( + id_shot_series SERIAL PRIMARY KEY, + score INTEGER NOT NULL, + photo VARCHAR(1024) NOT NULL, + id_participant_request INTEGER NOT NULL, + id_result_in_stage INTEGER NOT NULL, + id_judge_request INTEGER NOT NULL, + FOREIGN KEY (id_participant_request) REFERENCES participant_request(id_participant_request), + FOREIGN KEY (id_result_in_stage) REFERENCES result_in_stage(id_result_in_stage), + FOREIGN KEY (id_judge_request) REFERENCES judge_request(id_judge_request) +); diff --git a/fill_db_script/.gitignore b/fill_db_script/.gitignore new file mode 100644 index 0000000..ed8ebf5 --- /dev/null +++ b/fill_db_script/.gitignore @@ -0,0 +1 @@ +__pycache__ \ No newline at end of file diff --git a/fill_db_script/.vscode/launch.json b/fill_db_script/.vscode/launch.json new file mode 100644 index 0000000..afb3dac --- /dev/null +++ b/fill_db_script/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: main.py", + "type": "debugpy", + "request": "launch", + "program": "main.py", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/fill_db_script/competition_stage.csv b/fill_db_script/competition_stage.csv new file mode 100644 index 0000000..7e4ab8c --- /dev/null +++ b/fill_db_script/competition_stage.csv @@ -0,0 +1,8 @@ +title;count_of_series +. 1 ;30 +. 2 ;30 +1/16 ;6 +1/8 ;6 +1/4 ;6 +1/2 ;6 +;6 diff --git a/fill_db_script/division.csv b/fill_db_script/division.csv new file mode 100644 index 0000000..61ce9c7 --- /dev/null +++ b/fill_db_script/division.csv @@ -0,0 +1,17 @@ +title;gender;bow_type;distance;msmk;ms;kms;category_1;category_2;category_3 + . . 18 .;; ;18;586;570;530;500;455;415 + . . 18 .;; ;18;582;566;525;490;450;410 + . . 70 .;; ;70;670;640;615;580;530;500 + . . 70 .;; ;70;664;630;600;560;510;480 + . . 18 .;; ;18;586;570;530;500;455;415 + . . 18 .;; ;18;582;565;525;490;450;410 + . . 70 .;; ;70;685;660;640;610;555;525 + . . 70 .;; ;70;675;655;620;585;535;505 + . . 50 .;; ;50;586;570;530;500;455;415 + . . 50 .;; ;50;582;566;525;490;450;410 + . . 60 .;; ;60;670;640;615;580;530;500 + . . 60 .;; ;60;664;630;600;560;510;480 + . . 50 .;; ;50;586;570;530;500;455;415 + . . 50 .;; ;50;582;565;525;490;450;410 + . . 60 .;; ;60;685;660;640;610;555;525 + . . 60 .;; ;60;675;655;620;585;535;505 diff --git a/fill_db_script/judge.csv b/fill_db_script/judge.csv new file mode 100644 index 0000000..8dc27ca --- /dev/null +++ b/fill_db_script/judge.csv @@ -0,0 +1,51 @@ +surname;name;patronymic;category;region;federation +;;;;-; +;;;;-; +;;;;-; +;;;;-; +;;; ;-; +;;;;-; +;;; ;-; +;;; ; ; +;;;;-; +;;;;-; +;;;;-; +;;; ;-; +;;;;-; +;;;;-; +;;;;-; +;;;;-; +;;;;-; +;;;;-; +;;; ;-; +;;;;-; +;;; ;-; +;;; ;-; +;;;;-; +;;;;-; +;;;;-; +;;; ;-; +;;;;-; +;;;;-; +;;;;-; +;;;;-; +;;;;-; +;;;; ; +;;; ;-; +;;;;-; +;;; ;-; +;;; ;-; +;;;;-; +;;;;-; +;;;; ; +;;; ; ; +;;;; ; +;;;;-; +;;;;-; +;;;;-; +;;;;-; +;;;; ; +;;; ;-; +;;;;-; +;;; ;-; +;;; ; ; diff --git a/fill_db_script/main.py b/fill_db_script/main.py new file mode 100644 index 0000000..0ae6cbf --- /dev/null +++ b/fill_db_script/main.py @@ -0,0 +1,43 @@ +import time + +from utils import * + +# Параметры подключения к базе данных +conn_params = { + "dbname": "db_univer", + "user": "postgres", + "password": "123", + "host": "localhost", +} + + +if __name__ == "__main__": + delete_all_rows_from_all_tables(conn_params) + + start_time = time.perf_counter() + + # Заполняем таблицы первого уровня + load_csv_to_db(conn_params, "division", "division.csv") + load_csv_to_db(conn_params, "organizer", "organizer.csv") + load_csv_to_db(conn_params, "competition_stage", "competition_stage.csv") + load_csv_to_db(conn_params, "sportsman", "sportsman.csv", date_columns=[4]) + load_csv_to_db(conn_params, "judge", "judge.csv") + + # Второй уровень + generate_competitions(conn_params, 200) + + # Третий уровень + generate_protocols(conn_params) + generate_judge_requests(conn_params) + generate_participant_requests(conn_params) + generate_division_in_competitions(conn_params) + + # Четвёртый уровень + generate_result_in_stage(conn_params) + + # Пятый уровень + generate_shot_series(conn_params) + + print_rows_count_summary(conn_params) + + print(f"База данных заполнена за {time.perf_counter() - start_time:.3}с") diff --git a/fill_db_script/organizer.csv b/fill_db_script/organizer.csv new file mode 100644 index 0000000..91524fb --- /dev/null +++ b/fill_db_script/organizer.csv @@ -0,0 +1,21 @@ +name;logo + ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +" """"";https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + 21;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + | - ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + | , , ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + - ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +"- """"";https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +" "" """;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +" "" """;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +" """"";https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +Archer - . ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +" "" """;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +" "" """;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg +Archery Club;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg + ;https://static.tildacdn.com/tild3734-3334-4737-b432-383438313037/noroot.jpg diff --git a/fill_db_script/sportsman.csv b/fill_db_script/sportsman.csv new file mode 100644 index 0000000..70c4c93 --- /dev/null +++ b/fill_db_script/sportsman.csv @@ -0,0 +1,101 @@ +surname;name;patronymic;gender;birthday;region;club;federation;category +;;;;08.07.1993;-;;;/ +;;;;12.06.1991;-; ; ; +;;;;16.08.1984;-;; ; +;;;;02.04.1992;-;; ; +;;;;26.01.1989;-; ;;/ +;;;;23.02.1991;-; ;;/ +;;;;14.12.1960;-; ; ; +;;;;04.04.1977;-; ; ;/ +;;;;04.05.1988;-;;;2 +;;;;02.04.1992;-;; ; +;;;;08.10.1996;-;;;/ +;;;;30.03.1970; ; ; ;1 +;;;;03.09.2003;-; ;;/ +;;;;07.02.1983;-;;;1 +;;;;19.08.1979;-; ;;/ +;;;;03.09.2003;-; ;;/ +;;;;08.07.1993;-;;;/ +;;;;07.10.2002;-; ; ;1 +;;;;01.05.1983; ; ; ;1 +;;;;23.05.1989;-; ;;/ +;;;;19.08.1979;-; ;;/ +;;;;22.11.2004;-; ; ;2 +;;;;12.01.1996;-; ; ; +;;;;04.04.1977;-; ; ;/ +;;;;26.12.1979;-;; ; +;;;;04.05.1988;-;;;2 +;;;;08.05.1987;-; ; ; +;;;;14.02.1978; ;21; ; +;;;;09.01.1990;-;; ;1 +;;;;16.08.1984;-;; ; +;;;;12.06.1991;-; ; ; +;;;;27.07.1985;-;; ; +;;;;25.04.1978; ; ; ; +;;;;19.06.1990;-;; ;/ +;;Ը;;08.03.1990;-; ;;/ +;;;;12.07.1993;-;; ;1 +;;;;10.11.1984;-;; ;1 +;;;;12.01.1996;-; ; ; +;;;;01.08.2002;-; ;;/ +;;;;21.07.1992;-;; ; +;;;;23.05.1989;-; ;;/ +;;;;08.03.1979;-; ;;/ +;;;;17.09.1974;-;" """""; ;1 +;;;;01.05.1983; ; ; ;1 +;;Ը;;01.08.2002;-; ;;/ +;;;;08.05.1987;-; ; ; +;;;;07.02.1983;-;;;1 +;;;;14.02.1978; ;21; ; +;;;;12.01.1996;-; ; ; +;;;;19.06.1990;-;; ;/ +;;;;30.03.1970; ; ; ;1 +;;;;12.05.1992;-; ;;/ +;;;;04.02.1985;-;; ; +;;;;07.10.2002;-; ; ;1 +;;;;23.12.1999;-;" "" """; ; +;;;;27.10.1994;-;" "" """; ; +;;;;20.10.1989; ; ; ;/ +;;;;04.02.1985;-;; ; +;;;;25.04.1978; ; ; ; +;;;;22.11.1992;-; ;; +;;;;22.11.2004;-; ; ;2 +;;;;17.05.1988;-; ; ;1 +;;;;12.06.1991;-; ; ; +;ϸ;;;12.05.1992;-; ;;/ +;;;;25.04.1978; ; ; ; +;;;;22.11.1992;-; ;; +;;;;19.12.1976; ; ; ;/ +;;;;14.12.1960;-; ; ; +;;;;18.05.1992;-; ;;/ +;;;;09.07.2000;-; ;;/ +;;;;26.12.1979;-;; ; +;;;;22.11.1992;-; ;; +;;;;12.07.1993;-;; ;1 +;;;;23.12.1999;-;" "" """; ; +;;;;08.03.1979;-; ;;/ +;;;;23.02.1991;-; ;;/ +;;;;24.12.1989;-; ;; +;;;;27.10.1994;-;" "" """; ; +;;;;19.12.1976; ; ; ;/ +;;;;17.09.1974;-;" """""; ;1 +;;;;21.03.1986;-; ;;/ +;;;;04.02.1985;-;; ; +;;;;22.05.1990;-;; ; +;;;;09.01.1990;-;; ;1 +;;;;22.05.1990;-;; ; +;;;;09.07.2000;-; ;;/ +;;;;08.10.1996;-;;;/ +;;;;20.10.1989; ; ; ;/ +;;;;14.12.1960;-; ; ; +;;;;27.07.1985;-;; ; +;;;;10.11.1984;-;; ;1 +;;;;23.12.1999;-;" "" """; ; +;;;;21.07.1992;-;; ; +;;;;08.03.1990;-; ;;/ +;;;;01.08.2002;-; ;;/ +;;;;26.01.1989;-; ;;/ +;;;;24.12.1989;-; ;; +;;;;21.03.1986;-; ;;/ +;;;;18.05.1992;-; ;;/ +;;;;17.05.1988;-; ; ;1 diff --git a/fill_db_script/utils.py b/fill_db_script/utils.py new file mode 100644 index 0000000..203be52 --- /dev/null +++ b/fill_db_script/utils.py @@ -0,0 +1,452 @@ +import csv +import random +from datetime import datetime, timedelta + +import psycopg2 + + +def load_csv_to_db( + conn_params, table_name, csv_file_path, date_columns=None, delimiter=";" +): + """Добавляет данные из csv таблицы в указанную таблицу в бд. Важно, чтобы названия + столбцов и типы данных в таблицах совпадали. Преобразует даты в указанных столбцах. + """ + # Соединение с базой данных + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Открытие CSV-файла + with open(csv_file_path, mode="r", encoding="windows-1251") as file: + reader = csv.reader(file, delimiter=delimiter) + # Считывание заголовков для формирования SQL запроса + headers = next(reader) + + # Формирование строки запроса с плейсхолдерами для значений + placeholders = ", ".join(["%s"] * len(headers)) + insert_query = f"INSERT INTO {table_name} ({', '.join(headers)}) VALUES ({placeholders});" + + # Вставка данных в таблицу + for row in reader: + # Преобразование дат, если требуется + if date_columns: + for col_index in date_columns: + if row[col_index]: # Проверяем, не пустое ли значение + row[col_index] = datetime.strptime( + row[col_index], "%d.%m.%Y" + ).strftime("%Y-%m-%d") + cur.execute(insert_query, row) + conn.commit() + + +def print_rows_count_summary(conn_params): + """Выводит в консолько количество строк во всех таблицах в базе данных, а также + выводит суммарное количество всех строк в базе данных.""" + total_rows = 0 + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение списка всех таблиц в текущей базе данных + cur.execute( + """ + SELECT table_name + FROM information_schema.tables + WHERE table_schema = 'public' + """ + ) + tables = cur.fetchall() + + # Подсчет строк в каждой таблице + for (table_name,) in tables: + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + count = cur.fetchone()[0] + total_rows += count + print(f"Таблица {table_name}: {count} строк") + + print("Всего строк в базе данных: ", total_rows) + print() + + +def delete_all_rows_from_all_tables(conn_params): + """Очищает базу данных. Удаляет все строки из всех таблиц, но оставляет + сами таблицы.""" + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Отключение ограничений foreign key для избежания конфликтов при удалении + cur.execute("SET session_replication_role = 'replica';") + + # Получение списка всех таблиц в текущей базе данных + cur.execute( + """ + SELECT table_name + FROM information_schema.tables + WHERE table_schema = 'public' AND table_type = 'BASE TABLE' + """ + ) + tables = cur.fetchall() + + # Удаление всех строк из каждой таблицы + for (table_name,) in tables: + cur.execute(f"DELETE FROM {table_name}") + print(f"Все строки удалены из таблицы {table_name}") + + # Восстановление ограничений foreign key + cur.execute("SET session_replication_role = 'origin';") + + # Подтверждение всех изменений + conn.commit() + + print() + + +def generate_competitions(conn_params, num_records): + adjectives = [ + "Супер", + "Мега", + "Ультра", + "Эпический", + "Ежегодный", + "Ежеквартальный", + "Основной", + "Главный", + "Золотой", + "Платиновый", + ] + competition_types = [ + "кубок", + "чемпионат", + "марафон", + "турнир", + "фестиваль", + "конкурс", + "поединок", + ] + + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение списка ID организаторов + cur.execute("SELECT id_organizer FROM organizer") + organizer_ids = [row[0] for row in cur.fetchall()] + + for _ in range(num_records): + # Генерация случайного организатора + id_organizer = random.choice(organizer_ids) + + # Генерация случайных дат + start_date = datetime.now() - timedelta(days=random.randint(1, 5 * 365)) + end_date = start_date + timedelta(days=random.randint(1, 10)) + + # Форматирование дат для SQL + start_date = start_date.strftime("%Y-%m-%d") + end_date = end_date.strftime("%Y-%m-%d") + + # Генерация случайного названия + title = f"{random.choice(adjectives)} {random.choice(competition_types)} №{random.randint(1, 50)}" + + # Вставка данных в таблицу competition + cur.execute( + """ + INSERT INTO competition (title, address, logo, start_date, end_date, id_organizer) + VALUES (%s, %s, %s, %s, %s, %s); + """, + ( + title, + "Competition Address", + "Competition Logo", + start_date, + end_date, + id_organizer, + ), + ) + + conn.commit() + + +def generate_protocols(conn_params): + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение ID соревнований, которые еще не имеют протоколов + cur.execute( + """ + SELECT id_competition FROM competition + WHERE id_competition NOT IN (SELECT id_competition FROM protocol) + """ + ) + competition_ids = [row[0] for row in cur.fetchall()] + + for comp_id in competition_ids: + # Генерация случайной даты и имени файла + date = datetime.now() - timedelta(days=random.randint(1, 5 * 365)) + date = date.strftime("%Y-%m-%d") + file_name = f"protocol_{comp_id}.pdf" + + # Вставка данных в таблицу protocol + cur.execute( + """ + INSERT INTO protocol (name, date, file, id_competition) + VALUES (%s, %s, %s, %s); + """, + (f"Protocol for Competition {comp_id}", date, file_name, comp_id), + ) + + conn.commit() + + +def generate_judge_requests(conn_params): + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение списка всех соревнований + cur.execute("SELECT id_competition FROM competition") + competitions = [row[0] for row in cur.fetchall()] + + # Получение списка всех судей + cur.execute( + "SELECT id_judge, name, surname, patronymic, category, region, federation FROM judge" + ) + judges = cur.fetchall() + + for competition_id in competitions: + # Выбор случайного количества судей от 5 до 7 для каждого соревнования + selected_judges = random.sample(judges, random.randint(5, 7)) + + for judge in selected_judges: + ( + id_judge, + name, + surname, + patronymic, + category, + region, + federation, + ) = judge + # Определение статуса регистрации + is_registered = random.choices([True, False], [0.9, 0.1])[0] + + # Вставка данных в таблицу judge_request + cur.execute( + """ + INSERT INTO judge_request (name, surname, patronymic, category, region, federation, is_registered, id_competition, id_judge) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s); + """, + ( + name, + surname, + patronymic, + category, + region, + federation, + is_registered, + competition_id, + id_judge, + ), + ) + + conn.commit() + + +def generate_participant_requests(conn_params): + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение списка всех соревнований + cur.execute("SELECT id_competition FROM competition") + competitions = [row[0] for row in cur.fetchall()] + + # Получение списка всех спортсменов + cur.execute( + "SELECT id_sportsman, name, surname, patronymic, gender, birthday, region, club, federation, category FROM sportsman" + ) + sportsmen = cur.fetchall() + + for competition_id in competitions: + # Выбор случайного количества участников + selected_sportsmen = random.sample(sportsmen, random.randint(30, 60)) + + for sportsman in selected_sportsmen: + ( + id_sportsman, + name, + surname, + patronymic, + gender, + birthday, + region, + club, + federation, + category, + ) = sportsman + # Определение статуса регистрации + is_registered = random.choices([True, False], [0.9, 0.1])[0] + + # Выбор подходящих дивизионов с учетом гендера + cur.execute( + """ + SELECT id_division FROM division + WHERE gender = %s + """, + (gender,), + ) + divisions = [row[0] for row in cur.fetchall()] + + # Выбор случайного дивизиона из подходящих + id_division = random.choice(divisions) + + # Вставка данных в таблицу participant_request + cur.execute( + """ + INSERT INTO participant_request ( + name, surname, patronymic, gender, birthday, region, club, federation, category, is_registered, id_competition, id_sportsman, id_division + ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s); + """, + ( + name, + surname, + patronymic, + gender, + birthday, + region, + club, + federation, + category, + is_registered, + competition_id, + id_sportsman, + id_division, + ), + ) + + conn.commit() + + +def generate_division_in_competitions(conn_params): + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение списка всех соревнований + cur.execute("SELECT id_competition FROM competition") + competitions = [row[0] for row in cur.fetchall()] + + # Получение списка всех дивизионов + cur.execute("SELECT id_division FROM division") + divisions = [row[0] for row in cur.fetchall()] + + for competition_id in competitions: + # Выбор случайного количества дивизионов + selected_divisions = random.sample(divisions, random.randint(8, 16)) + + for division_id in selected_divisions: + # Вставка данных в таблицу division_in_competition + cur.execute( + """ + INSERT INTO division_in_competition (id_division, id_competition) + VALUES (%s, %s); + """, + (division_id, competition_id), + ) + + conn.commit() + + +def generate_result_in_stage(conn_params): + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение списка всех заявок участников + cur.execute( + """ + SELECT id_participant_request, id_division + FROM participant_request + """ + ) + participant_requests = cur.fetchall() + + # Получение списка всех этапов соревнований + cur.execute("SELECT id_competition_stage FROM competition_stage") + competition_stages = [row[0] for row in cur.fetchall()] + + for request in participant_requests: + id_participant_request, id_division = request + # Количество результатов для каждой заявки + num_results = random.randint(2, 6) + + for _ in range(num_results): + score = random.randint(150, 300) + shield_index = random.randint(0, 20) + target_index = random.choice(["A", "B", "C", "D"]) + id_competition_stage = random.choice(competition_stages) + + # Вставка данных в таблицу result_in_stage + cur.execute( + """ + INSERT INTO result_in_stage (score, shield_index, target_index, id_participant_request, id_division, id_competition_stage) + VALUES (%s, %s, %s, %s, %s, %s); + """, + ( + score, + shield_index, + target_index, + id_participant_request, + id_division, + id_competition_stage, + ), + ) + + conn.commit() + + +def generate_shot_series(conn_params): + with psycopg2.connect(**conn_params) as conn: + with conn.cursor() as cur: + # Получение всех записей result_in_stage и связанных с ними данных + cur.execute( + """ + SELECT rs.id_result_in_stage, rs.id_participant_request, pr.id_competition + FROM result_in_stage rs + JOIN participant_request pr ON rs.id_participant_request = pr.id_participant_request + """ + ) + results = cur.fetchall() + + # Получение id судей с учетом id_competition + cur.execute( + """ + SELECT id_judge_request, id_competition FROM judge_request + """ + ) + judges = cur.fetchall() + + # Сопоставление судей с соревнованиями + judge_map = {} + for judge_id, comp_id in judges: + if comp_id in judge_map: + judge_map[comp_id].append(judge_id) + else: + judge_map[comp_id] = [judge_id] + + for result in results: + id_result_in_stage, id_participant_request, id_competition = result + + # Выбор случайного судьи для данного соревнования + if id_competition in judge_map: + id_judge_request = random.choice(judge_map[id_competition]) + else: + # Если нет судьи для соревнования, пропускаем + raise KeyError(f"Нету судей для соревнования {id_competition}") + + # Выбираем случайное количество серий выстрелов + num_shot_series = random.randint(3, 10) + + for _ in range(num_shot_series): + score = random.randint(2, 10) + photo = "path/to/photo.jpg" # Пример пути к фото + + # Вставка данных в таблицу shot_series + cur.execute( + """ + INSERT INTO shot_series (score, photo, id_participant_request, id_result_in_stage, id_judge_request) + VALUES (%s, %s, %s, %s, %s); + """, + ( + score, + photo, + id_participant_request, + id_result_in_stage, + id_judge_request, + ), + ) + + conn.commit() diff --git a/function1.sql b/function1.sql new file mode 100644 index 0000000..53efce3 --- /dev/null +++ b/function1.sql @@ -0,0 +1,17 @@ +create or replace function convert_to_initials( + p_name varchar, + p_surname varchar, + p_patronymic varchar +) returns varchar as $$ +begin + if p_name is null or p_name = '' or p_surname is null or p_surname = '' then + return ''; + end if; + + if p_patronymic is null or p_patronymic = '' then + return concat(substring(p_name from 1 for 1), '. ', p_surname); + end if; + + return concat(substring(p_patronymic from 1 for 1), '. ', substring(p_name from 1 for 1), '. ', p_surname); +end; +$$ language plpgsql; \ No newline at end of file diff --git a/function2.sql b/function2.sql new file mode 100644 index 0000000..354ab43 --- /dev/null +++ b/function2.sql @@ -0,0 +1,8 @@ +select + id_judge, + convert_to_initials (name, surname, patronymic), + name, + surname, + patronymic +from + judge \ No newline at end of file diff --git a/procedure.sql b/procedure.sql new file mode 100644 index 0000000..656f7f3 --- /dev/null +++ b/procedure.sql @@ -0,0 +1,67 @@ +-- select +-- * +-- from +-- participant_request +-- where +-- name = 'Дмитрий' +-- and surname = 'Малышев' +-- and id_competition = ( +-- select id_competition from competition where title = 'Мега кубок №36' limit 1 +-- ) + + +create or replace procedure create_participant_request( + p_name varchar(100), + p_surname varchar(100), + p_gender varchar(10), + p_competition_title varchar(100), + p_division_title varchar(100) +) +language plpgsql +as $$ +declare + v_id_sportsman integer; + v_id_competition integer; + v_id_division integer; +begin + -- проверка существования дивизиона + select id_division into v_id_division + from division + where title = p_division_title + limit 1; + + if not found then + raise exception 'Дивизиона % не существует', p_division_title; + end if; + + -- проверка существования соревнования + select id_competition into v_id_competition + from competition + where title = p_competition_title + limit 1; + + -- если соревнование не существует, создать его + if not found then + insert into competition (title) + values (p_competition_title) + returning id_competition into v_id_competition; + end if; + + -- проверка существования спортсмена + select id_sportsman into v_id_sportsman + from sportsman + where name = p_name and surname = p_surname and gender = p_gender + limit 1; + + -- если спортсмен не существует, создать его + if not found then + insert into sportsman (name, surname, gender) + values (p_name, p_surname, p_gender) + returning id_sportsman into v_id_sportsman; + end if; + + -- создание заявки участника + insert into participant_request (name, surname, gender, is_registered, id_competition, id_sportsman, id_division) + values (p_name, p_surname, p_gender, false, v_id_competition, v_id_sportsman, v_id_division); +end; +$$; \ No newline at end of file diff --git a/report.tex b/report/report.tex similarity index 100% rename from report.tex rename to report/report.tex diff --git a/triggers.sql b/triggers.sql new file mode 100644 index 0000000..708a91c --- /dev/null +++ b/triggers.sql @@ -0,0 +1,107 @@ +-- запросы для проверки триггеров +-- select * from judge_statistics; + +-- insert into judge (name, category, region, federation) +-- values ('Иван Иванов', '1 категория', 'Санкт-Петербург', 'Федерация'); +-- select * from judge where name = 'Иван Иванов'; +-- select * from judge_statistics where id_judge = 154; + +-- insert into judge_request (name, category, region, federation, is_registered, id_competition, id_judge) +-- values ('Иван Иванов', '1 категория', 'Санкт-Петербург', 'Федерация', true, 401, 1); +-- update judge_request set id_judge = 2 where id_judge = 1; +-- delete from judge_request where name = 'Иван Иванов'; + +-- delete from judge where name = 'Иван Иванов'; + +-- таблица для ведения статистики +create table judge_statistics ( + id_judge integer primary key, + competition_count integer not null default 0, + foreign key (id_judge) references judge(id_judge) +); + + +-- добавление судьи +create or replace function update_statistics_on_judge_insert() +returns trigger as $$ +begin + insert into judge_statistics (id_judge, competition_count) + values (new.id_judge, 0); + return new; +end; +$$ language plpgsql; + +create trigger after_judge_insert +after insert on judge +for each row +execute function update_statistics_on_judge_insert(); + +-- удаление судьи +create or replace function update_statistics_on_judge_delete() +returns trigger as $$ +begin + delete from judge_statistics where id_judge = old.id_judge; + return old; +end; +$$ language plpgsql; + +create trigger after_judge_delete +after delete on judge +for each row +execute function update_statistics_on_judge_delete(); + +-- добавление заявки судьи +create or replace function update_statistics_on_judge_request_insert() +returns trigger as $$ +begin + update judge_statistics + set competition_count = competition_count + 1 + where id_judge = new.id_judge; + return new; +end; +$$ language plpgsql; + +create trigger after_judge_request_insert +after insert on judge_request +for each row +execute function update_statistics_on_judge_request_insert(); + +-- удаление заявки судьи +create or replace function update_statistics_on_judge_request_delete() +returns trigger as $$ +begin + update judge_statistics + set competition_count = competition_count - 1 + where id_judge = old.id_judge; + return old; +end; +$$ language plpgsql; + +create trigger after_judge_request_delete +after delete on judge_request +for each row +execute function update_statistics_on_judge_request_delete(); + + +-- обновление заявки судьи +create or replace function update_statistics_on_judge_request_update() +returns trigger as $$ +begin + -- уменьшение счётчика у старого судьи + update judge_statistics + set competition_count = competition_count - 1 + where id_judge = old.id_judge; + + -- увеличение счётчика у нового судьи + update judge_statistics + set competition_count = competition_count + 1 + where id_judge = new.id_judge; + + return new; +end; +$$ language plpgsql; + +create trigger after_judge_request_update +after update on judge_request +for each row +execute function update_statistics_on_judge_request_update(); \ No newline at end of file diff --git a/view1.sql b/view1.sql new file mode 100644 index 0000000..3456683 --- /dev/null +++ b/view1.sql @@ -0,0 +1,17 @@ +-- Для каждого спортсмена посчитать число заявок и число серий +create view + sportsman_requests_series_count as +select + s.id_sportsman, + count(distinct pr.id_participant_request) as pr_count, + count(ss.id_shot_series) as ss_count +from + sportsman as s + left join participant_request as pr on s.id_sportsman = pr.id_sportsman + left join shot_series as ss on pr.id_participant_request = ss.id_participant_request +group by + s.id_sportsman + + +-- insert into sportsman_requests_series_count (id_sportsman, pr_count, ss_count) values (1, 2, 3) +-- update sportsman_requests_series_count set pr_count = 5, ss_count = 10 where id_sportsman = 201 \ No newline at end of file diff --git a/view2.sql b/view2.sql new file mode 100644 index 0000000..9dfd2d1 --- /dev/null +++ b/view2.sql @@ -0,0 +1,16 @@ +-- Запрос с использованием view + +select + srsc.id_sportsman, + s.name, + srsc.pr_count, + srsc.ss_count +from + sportsman_requests_series_count as srsc + join sportsman as s on srsc.id_sportsman = s.id_sportsman +where + s.gender = 'Мужчина' + and s.club = 'ЛК Парадокс Лучника' +order by + srsc.pr_count desc +limit 10; \ No newline at end of file diff --git a/view3.sql b/view3.sql new file mode 100644 index 0000000..2ccf1c0 --- /dev/null +++ b/view3.sql @@ -0,0 +1,15 @@ +-- Создание пользователей и выдача им прав + +create user readonly_user with password '123'; +grant usage on schema public to readonly_user; +grant select on sportsman_requests_series_count to readonly_user; + +create user edit_user with password '123'; +grant usage on schema public to edit_user; +grant select on sportsman_requests_series_count to edit_user; +grant select, insert, update, delete on sportsman to edit_user; +grant select, insert, update, delete on participant_request to edit_user; +grant select, insert, update, delete on shot_series to edit_user; +grant usage, select on sequence sportsman_id_sportsman_seq to edit_user; +grant usage, select on sequence participant_request_id_participant_request_seq to edit_user; +grant usage, select on sequence shot_series_id_shot_series_seq to edit_user; \ No newline at end of file