diff --git a/Project/11.12.2024_05.55.52_REC.png b/Project/11.12.2024_05.55.52_REC.png
new file mode 100644
index 0000000..70cb058
Binary files /dev/null and b/Project/11.12.2024_05.55.52_REC.png differ
diff --git a/Project/README.md b/Project/README.md
index 7395f6d..6ae4bda 100644
--- a/Project/README.md
+++ b/Project/README.md
@@ -48,5 +48,103 @@ _**ТРАНСПОРТ**_ : НАЗВАНИЕ, ТИП, СОСТОЯНИЕ
- Инфо логическая модель
- Дата логическая модель
-
-
+## 3. Улучшение структуры БД
+
+### Нормальная форма (Database normalization)
+Под. Описание [wikipedia](https://ru.wikipedia.org/wiki/%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0)
+
+Нормализация позволяет оптимально распределять атрибуты по таблицам. Данная методика избавляет от:
+- атрибутов с несколькими значениями;
+- повторяющихся атрибутов;
+- атрибутов, не поддающихся классификации;
+- атрибутов с избыточной информацией;
+- атрибутов, созданных из других признаков.
+
+1. Первая нормальная форма (1NF)
+Таблица находится в 1NF, если она имеет Атомарные значения (нет повторяющихся групп или массивов) и
+Каждая строка уникально идентифицируется первичным ключом.
+Мои схемы уже соответствуют 1NF, так как каждый столбец содержит атомарные значения, и первичные ключи определены для всех таблиц.
+
+2. Вторая нормальная форма (2NF)
+Таблица находится во 2NF, если:
+Она находится в 1NF.
+Все неключевые атрибуты полностью функционально зависят от первичного ключа (нет частичной зависимости).
+Мои схемы уже соответствуют 2NF.
+
+3. Третья нормальная форма (3NF)
+Таблица находится в 3NF, если:
+Она находится в 2NF.
+Нет транзитивной зависимости, что означает, что неключевые атрибуты не должны зависеть от других неключевых атрибутов.
+
+Таблица сотрудников: таблица включает ссылку на внешний ключ base_id, что можно считать транзитивной зависимостью.
+Вместо того чтобы напрямую хранить base_id, могу создать новую таблицу, которая связывает сотрудников с их базой, и удалить прямую ссылку из таблицы сотрудников.
+Чтобы решить эту проблему, создаю отдельную таблицу employee_base:
+
+```sql
+CREATE TABLE employee_base (
+ emp_id INTEGER NOT NULL REFERENCES employee ON DELETE CASCADE,
+ base_id INTEGER NOT NULL REFERENCES base ON DELETE SET NULL,
+ PRIMARY KEY (emp_id, base_id)
+);
+```
+
+Это устраняет транзитивную зависимость от base_id в таблице сотрудников и улучшает 3NF.
+
+4. Нормальная форма Бойса-Кодда (BCNF)
+Таблица находится в BCNF, если:
+Она находится в 3NF.
+Для каждой нетривиальной функциональной зависимости детерминант является кандидатом в ключи.
+Таблица employee_base, описанная выше, поможет обеспечить отсутствие нетривиальных функциональных зависимостей, нарушающих BCNF.
+
+После этого, давайте подумаем о том, какие запросы будут наиболее часто используемыми (востребованными) для этой базы данных. В моем случае, я думаю, что нам обычно потребуется:
+- Извлекать данные о сотрудниках, обновлять их и получать информацию о здоровье сотрудников,
+- знать о различных миссиях, доходах и клиентах,
+- а также о состоянии нашего транспорта.
+Основываясь на этом, давайте используем некоторые полезные методы для повышения производительности этой базы данных:
+
+### Временные структуры и представления, способы валидации запросов
+- Представления (Views) и Материализованные представления (Materialized Views)
+
Материализованное представление в базе данных функционирует аналогично обычному представлению, но с одним важным отличием: оно кэширует результат запроса представления,
+
сохраняя его в виде физической таблицы. Это означает, что в отличие от стандартного представления, при котором базовый запрос выполняется при каждом обращении к нему,
+
материализованное представление отображает сохраненные данные до тех пор, пока они не будут обновлены. Это может значительно повысить производительность сложных запросов, для которых не требуются данные в реальном времени.
+
+### Индексы (Indexes)
+Сначала я проверила часто используемые столбцы и создала выборку некоторых индексов, которые, по моему мнению, будут важны для повышения производительности базы данных.
+Отметим, что я выбрала хэш-индекс для столбцов, основанных на идентификаторах, потому что:
+1. Хэш-индексы(hash index) оптимизированы для поиска равенства (например, WHERE id = ?), что характерно для столбцов ID.
+2. Хэш-индексы обеспечивают быстрое время поиска при средней временной сложности O(1), что делает их подходящими для первичных ключей и уникальных идентификаторов.
+
Поскольку столбцы идентификаторов часто используются в точных совпадениях (=), хэш-индексы могут эффективно обрабатывать эти запросы.
+
С другой стороны:
+1. Индексы B-дерева(b-tree) подходят для запросов диапазона (например, WHERE column > ? или WHERE column BETWEEN ? И ?), что характерно для столбцов без идентификатора.
+2. Индексы B-дерева поддерживают эффективную сортировку и упорядочение, что делает их идеальными для столбцов, используемых в предложениях ORDER BY и GROUP BY.
+3. Индексы B-дерева могут выполнять поиск как по равенству(=), так и по диапазону(<...>), что делает их хорошим выбором для столбцов с различными шаблонами запросов.
+
Иногда индексы не всегда работают должным образом. Или мы можем создавать индексы, которые на самом деле не важны для базы данных. Итак, я решила провести некоторые проверки, которые позволили бы удалить неиспользуемые индексы.
+```sql
+SELECT relname , indexrelname , idx_scan , idx_tup_read , idx_tup_fetch
+FROM pg_stat_user_indexes
+WHERE schemaname = 'public' and
+ relname in ('campaign');
+```
+### Общие табличные выражения (CTE) и Временные таблицы (Temporary Tables)
+CTE и временные таблицы имеют общие цели. Обе они генерируют промежуточные результаты для запроса,
+
не оставляя постоянных объектов в базе данных; это экономит место для хранения. Но между ними есть важные различия: для CTE повторное использование кода ограничено одним запросом.
С другой стороны, данные, хранящиеся во временной таблице, могут многократно использоваться в различных запросах. Ключевым требованием является то, что эти запросы выполняются в рамках одного и того же подключения к базе данных (сеанса).
+Я выбрала (CTE) для сводки (по состоянию здоровья сотрудников и доступности транспорта), потому что это упрощает запрос и делает его более читаемым.
+
Они также позволяют разделить сложную логику на более мелкие и управляемые части.
+
С другой стороны, я выбрал временную таблицу для определения наличия рабочих мест, поскольку она позволяет хранить промежуточные результаты и манипулировать ими,
+
которые можно использовать несколько раз в запросе (например, в течение дня, если где-то требуется дополнительный сотрудник) или в нескольких запросах.
+
+- EXPLAIN ANALYZE
+
EXPLAIN: предоставляет вам подробный план запроса, который показывает, как PostgreSQL планирует выполнить ваш SQL-запрос.
+
Можно запустить EXPLAIN перед запросом SELECT, чтобы увидеть, какие шаги предпримет PostgreSQL для извлечения данных (например, использует ли он индекс, выполняет ли последовательное сканирование, объединяет и т.д.).
+
EXPLAIN ANALYZE: фактически запускает запрос и показывает реальное время выполнения, помогая вам понять, насколько эффективно выполняется запрос. Он также показывает количество строк, обработанных на каждом шаге.
+Пример использования до и после один из индексов. Можно заметить что время выполнения запроса время выполнения уменш.
+
+
+- VACUUM
+
PostgreSQL использует систему версионирования (MVCC), поэтому, когда строки обновляются или удаляются,
+диск не освобождается немедленно. Со временем это может привести к раздуванию таблицы.
+Запуск VACUUM помогает вернуть пространство и также может улучшить производительность.
+
VACUUM: Освобождает место и анализирует таблицу для обновления статистики.
+
VACUUM FULL: Полностью переписывает таблицу, освобождая пространство, но является более затратным и может блокировать таблицу на некоторое время.
+
+## 4. Триггеры и транзакции
diff --git a/Project/data_population.sql b/Project/data_population.sql
new file mode 100644
index 0000000..f2244ce
--- /dev/null
+++ b/Project/data_population.sql
@@ -0,0 +1,201 @@
+-- -- Insert into base
+-- INSERT INTO base (location, status) VALUES
+-- ('Base A', 'OPEN'),
+-- ('Base B', 'OPEN'),
+-- ('Base C', 'CLOSED'),
+-- ('Base D', 'OPEN'),
+-- ('Base Burny', 'OPEN'),
+-- ('Base Alfa', 'CLOSED'),
+-- ('Base Dunky', 'OPEN'),
+-- ('Base Elf', 'OPEN');
+--
+-- -- Insert into mre
+-- INSERT INTO mre (breakfast, lunch, dinner, food_additives, kkal, proteins, fats, carbohydrate) VALUES
+-- ('Oatmeal', 'Chicken Stew', 'Beef Stew', 'None', 3500, 100, 60, 300),
+-- ('Pasta', 'Tuna Salad', 'Vegetable Curry', 'Spices', 4000, 120, 70, 350),
+-- ('Rice', 'Beef Stroganoff', 'Chicken Curry', 'None', 4500, 110, 80, 320),
+-- ('Cereal', 'Vegetable Soup', 'Pork Chops', 'None', 3700, 90, 50, 280),
+-- ('Granola', 'Fish Tacos', 'Chili', 'Hot Sauce', 3900, 95, 55, 310);
+--
+-- -- Insert into equipment
+-- INSERT INTO equipment (camouflage, communication, intelligence, medical, mre_id, extra) VALUES
+-- ('Woodland', 'Radio', 'Drones', 'First Aid Kit', 1, 'Extra Batteries'),
+-- ('Desert', 'Satellite Phone', 'Recon', 'Medical Supplies', 2, 'GPS Device'),
+-- ('Urban', 'Walkie Talkie', 'Surveillance', 'Trauma Kit', 3, 'Night Vision Goggles'),
+-- ('Jungle', 'Signal Flare', 'Recon', 'First Aid Kit', 4, 'Binoculars'),
+-- ('Snow', 'Radio', 'Drones', 'Medical Supplies', 5, 'Thermal Blanket');
+--
+-- -- Insert into position
+-- INSERT INTO position (name, salary_rub, rank, equip_id, forces) VALUES
+-- ('Infantry Soldier', 60000, 'Private', 1, 'GF'),
+-- ('Sniper', 80000, 'Corporal', 2, 'NAVY'),
+-- ('Medic', 70000, 'Sergeant', 3, 'AF'),
+-- ('Engineer', 90000, 'Lieutenant', 4, 'GF'),
+-- ('Pilot', 120000, 'Captain', 5, 'NAVY');
+--
+-- -- Insert into employee
+-- INSERT INTO employee (name, surname, date_of_birth, education, pos_id, is_married, base_id) VALUES
+-- ('John', 'Doe', '1990-01-15', 'High School', 1, TRUE, 1),
+-- ('Jane', 'Smith', '1985-05-20', 'Bachelor', 2, FALSE, 1),
+-- ('Alice', 'Johnson', '1992-03-10', 'Bachelor', 3, TRUE, 2),
+-- ('Bob', 'Brown', '1988-07-25', 'Master', 4, FALSE, 2),
+-- ('Charlie', 'Davis', '1980-12-30', 'PhD', 5, TRUE, 3),
+-- ('David', 'Wilson', '1995-11-11', 'High School', 1, FALSE, 3),
+-- ('Eva', 'Garcia', '1987-09-09', 'Bachelor', 2, TRUE, 4),
+-- ('Frank', 'Martinez', '1993-04-04', 'Master', 3, FALSE, 4),
+-- ('Grace', 'Hernandez', '1982-06-06', 'PhD', 4, TRUE, 5),
+-- ('Henry', 'Lopez', '1991-08-08', 'High School', 5, FALSE, 5),
+-- ('Isabella', 'Gonzalez', '1989-02-02', 'Bachelor', 1, TRUE, 1),
+-- ('Jack', 'Wilson', '1986-10-10', 'Master', 2, FALSE, 1),
+-- ('Liam', 'Anderson', '1994-12-12', 'PhD', 3, TRUE, 2),
+-- ('Mia', 'Thomas', '1983-03-03', 'High School', 4, FALSE, 2),
+-- ('Noah', 'Taylor', '1990-05-05', 'Bachelor', 5, TRUE, 3),
+-- ('Olivia', 'Moore', '1988-07-07', 'Master', 1, FALSE, 3),
+-- ('Paul', 'Jackson ', '1992-08-08', 'PhD', 2, TRUE, 4),
+-- ('Quinn', 'White', '1985-09-09', 'High School', 3, FALSE, 4),
+-- ('Riley', 'Harris', '1993-10-10', 'Bachelor', 4, TRUE, 5),
+-- ('Sophia', 'Martin', '1981-11-11', 'Master', 5, FALSE, 5),
+-- ('Thomas', 'Thompson', '1990-12-12', 'PhD', 1, TRUE, 1),
+-- ('Uma', 'Garcia', '1986-01-01', 'High School', 2, FALSE, 1),
+-- ('Victor', 'Martinez', '1994-02-02', 'Bachelor', 3, TRUE, 2),
+-- ('Wendy', 'Robinson', '1989-03-03', 'Master', 4, FALSE, 2),
+-- ('Xander', 'Clark', '1982-04-04', 'PhD', 5, TRUE, 3),
+-- ('Yara', 'Rodriguez', '1991-05-05', 'High School', 1, FALSE, 3),
+-- ('Zoe', 'Lewis', '1987-06-06', 'Bachelor', 2, TRUE, 4);
+--
+-- -- Insert into medical_card
+-- INSERT INTO medical_card (emp_id, height_cm, weight_kg, diseases, blood, gender) VALUES
+-- (1, 180, 75, 'Diabet', 'A', 'M'),
+-- (2, 165, 60, 'None', 'B', 'F'),
+-- (3, 170, 65, 'Infulenza', 'O', 'F'),
+-- (4, 175, 80, 'Malaria, Diabet', 'AB', 'M'),
+-- (5, 185, 90, 'None', 'AO', 'M'),
+-- (6, 160, 55, 'None', 'BO', 'F'),
+-- (7, 178, 70, 'None', 'A', 'M'),
+-- (8, 172, 68, 'Influenza, Gripp', 'B', 'F'),
+-- (9, 169, 62, 'None', 'O', 'F'),
+-- (10, 182, 85, 'None', 'AB', 'M'),
+-- (11, 177, 72, 'Gripp', 'AO', 'F'),
+-- (12, 165, 58, 'None', 'BO', 'F'),
+-- (13, 180, 78, 'None', 'A', 'M'),
+-- (14, 173, 66, 'None', 'B', 'F'),
+-- (15, 168, 64, 'Malaria, Gripp', 'O', 'F'),
+-- (16, 184, 88, 'None', 'AB', 'M'),
+-- (17, 176, 74, 'None', 'AO', 'F'),
+-- (18, 162, 57, 'Typhoid', 'BO', 'F'),
+-- (19, 179, 77, 'None', 'A', 'M'),
+-- (20, 171, 69, 'None', 'B', 'F'),
+-- (21, 167, 63, 'Tyhoid, Malaria', 'O', 'F'),
+-- (22, 183, 86, 'None', 'AB', 'M'),
+-- (23, 175, 73, 'None', 'AO', 'F'),
+-- (24, 164, 59, 'None', 'BO', 'F'),
+-- (25, 181, 82, 'None', 'A', 'M');
+--
+-- -- Insert into weapon
+-- INSERT INTO weapon (name, type, caliber, rate_of_fire, sighting_range_m) VALUES
+-- ('AK-47', 'Assault Rifle', 7.62, 600, 400),
+-- ('M4 Carbine', 'Assault Rifle', 5.56, 700, 500),
+-- ('M16', 'Assault Rifle', 5.56, 800, 600),
+-- ('Glock 17', 'Pistol', 9.0, 1200, 50),
+-- ('M249 SAW', 'Light Machine Gun', 5.56, 1000, 800);
+--
+-- -- Insert into campaign
+-- INSERT INTO campaign (name, customer, earning, spending, execution_status) VALUES
+-- ('Operation Alpha', 'Department of Defense', 100762500, 500000, 'STARTED'),
+-- ('Operation Bravo', 'NATO', 2000000, 1500000, 'ON_GOING'),
+-- ('Operation Charlie 1', 'Private Contractor', 1500860, 800000, 'PENDING'),
+-- ('Operation Bravo', 'Private Agency', 2000000, 1500000, 'ON_GOING'),
+-- ('Operation Camar', 'Private Contractor', 1500000, 800000, 'PENDING'),
+-- ('Operation Bravo', 'NATO', 2000000, 500000, 'ON_GOING'),
+-- ('Operation Charlie 2', 'Private Contractor', 33300000, 800000, 'PENDING'),
+-- ('Operation Bravo 1', 'NATO', 2000000, 150000, 'ON_GOING'),
+-- ('Operation Eagle', 'Private Contractor', 21500000, 800000, 'PENDING'),
+-- ('Operation Delta', 'Local Government', '500000', '200000', 'FINISHED'),
+-- ('Operation Echo', 'Private Contractor', 750000, 300000, 'NOT_STARTED');
+--
+-- -- Insert into mission
+-- INSERT INTO mission (camp_id, start_date_and_time, end_date_and_time, legal_status, departure_location, arrival_location, enemies) VALUES
+-- (1, '2023-01-01 08:00:00', '2023-01-10 18:00:00', TRUE, 'Base A', 'Base B', 'Enemy Forces A'),
+-- (2, '2023-02-01 09:00:00', '2023-02-15 17:00:00', TRUE, 'Base B', 'Base C', 'Enemy Forces B'),
+-- (3, '2023-03-01 10:00:00', '2023-03-20 16:00:00', FALSE, 'Base C', 'Base D', 'Enemy Forces C'),
+-- (4, '2023-04-01 11:00:00', '2023-04-25 15:00:00', TRUE, 'Base D', 'Base E', 'Enemy Forces D'),
+-- (5, '2023-05-01 12:00:00', '2023-05-30 14:00:00', TRUE, 'Base E', 'Base A', 'Enemy Forces E');
+--
+-- -- Insert into transport
+-- INSERT INTO transport (name, type, status) VALUES
+-- ('Transport Vehicle 1', 'Truck', 'VERIFIED'),
+-- ('Transport Vehicle 2', 'Helicopter', 'NEED_VERIFICATION'),
+-- ('Transport Vehicle 3', 'Boat', 'MAINTAINED'),
+-- ('Transport Vehicle 4', 'Tank', 'NOT_MAINTAINED'),
+-- ('Transport Vehicle 5', 'Drone', 'OUT_OF_USE');
+--
+-- -- Insert into equip_weapon
+-- INSERT INTO equip_weapon (equip_id, weapon_id) VALUES
+-- (1, 1),
+-- (2, 2),
+-- (3, 3),
+-- (4, 4),
+-- (5, 5);
+--
+-- -- Insert into missions_transport
+-- INSERT INTO missions_transport (miss_id, trans_id) VALUES
+-- (1, 1),
+-- (2, 2),
+-- (3, 3),
+-- (4, 4),
+-- (5, 5);
+--
+-- -- Insert into inspection
+-- INSERT INTO inspection (emp_id, trans_id, service_date) VALUES
+-- (1, 1, '2023-01-05'),
+-- (2, 2, '2023-02-05'),
+-- (3, 3, '2023-03-05'),
+-- (4, 4, '2023-04-05'),
+-- (5, 5, '2023-05-05');
+--
+-- -- Insert into missions_emp
+-- INSERT INTO missions_emp (miss_id, emp_id) VALUES
+-- (1, 1),
+-- (1, 2),
+-- (2, 3),
+-- (2, 4),
+-- (3, 5),
+-- (4, 1),
+-- (4, 3),
+-- (5, 2),
+-- (5, 4),
+-- (5, 5);
+-- Insert into transport (additional entries)
+-- select * from mission;
+-- INSERT INTO transport (name, type, status) VALUES
+-- ('Transport Vehicle 6', 'Armored Personnel Carrier', 'VERIFIED'),
+-- ('Transport Vehicle 7', 'Cargo Plane', 'NEED_VERIFICATION'),
+-- ('Transport Vehicle 8', 'Submarine', 'MAINTAINED'),
+-- ('Transport Vehicle 9', 'ATV', 'NOT_MAINTAINED'),
+-- ('Transport Vehicle 10', 'Helicopter', 'OUT_OF_USE'),
+-- ('Transport Vehicle 11', 'Military Truck', 'VERIFIED'),
+-- ('Transport Vehicle 12', 'Fast Boat', 'MAINTAINED'),
+-- ('Transport Vehicle 13', 'Recon Drone', 'NEED_VERIFICATION'),
+-- ('Transport Vehicle 14', 'Mobile Command Center', 'OUT_OF_USE'),
+-- ('Transport Vehicle 15', 'Transport Helicopter', 'MAINTAINED');
+-- -- Insert into weapon (additional entries)
+-- INSERT INTO weapon (name, type, caliber, rate_of_fire, sighting_range_m) VALUES
+-- ('FN SCAR', 'Assault Rifle', 7.62, 600, 600),
+-- ('MP5', 'Submachine Gun', 9.0, 800, 200),
+-- ('Desert Eagle', 'Pistol', 0.50, 300, 50),
+-- ('M240', 'Machine Gun', 7.62, 1000, 800),
+-- ('RPG-7', 'Rocket Launcher', 40.0, 0, 300),
+-- ('Tavor X95', 'Assault Rifle', 5.56, 900, 500),
+-- ('M1014', 'Shotgun', 12.0, 1200, 50),
+-- ('M14', 'Battle Rifle', 7.62, 700, 800),
+-- ('SIG P226', 'Pistol', 9.0, 1000, 50),
+-- ('M107', 'Sniper Rifle', 12.7, 1, 2000);
+--
+-- -- Insert into mission (additional entries)
+-- INSERT INTO mission (camp_id, start_date_and_time, end_date_and_time, legal_status, departure_location, arrival_location, enemies) VALUES
+-- (6, '2023-06-01 08:59:00', '2023-06-10 18:30:00', TRUE, 'Base A', 'Base C', 'Enemy Forces F'),
+-- (7, '2023-07-01 09:05:00', '2023-07-15 17:00:00', FALSE, 'Base B', 'Base D', 'Enemy Forces G'),
+-- (8, '2023-08-01 10:08:00', '2023-08-20 16:00:00', TRUE, 'Base C', 'Base E', 'Enemy Forces H'),
+-- (9, '2023-09-01 11:10:00', '2023-09-25 15:20:00', TRUE, 'Base D', 'Base A', 'Enemy Forces I'),
+-- (10, '2023-10-01 12:00:00', '2023-10-30 14:00:00', FALSE, 'Base E', 'Base B', 'Enemy Forces J'),
+-- (11, '2023-11-01 08:00:00', '2023-11-10 18:03:00', TRUE, 'Base A', 'Base D', 'Enemy Forces K');
\ No newline at end of file
diff --git a/Project/part1.sql b/Project/part1.sql
index da95c54..d04a461 100644
--- a/Project/part1.sql
+++ b/Project/part1.sql
@@ -53,10 +53,10 @@ CREATE TYPE force_category AS ENUM ('GF', 'NAVY', 'AF');
CREATE TABLE position
(
pos_id SERIAL PRIMARY KEY,
- name VARCHAR(255) NOT NULL,
+ name VARCHAR(255) NOT NULL,
salary_rub NUMERIC(10, 2) NOT NULL CHECK (salary_rub >= 50000),
rank VARCHAR(100),
- equip_id INTEGER REFERENCES equipment ON DELETE SET NULL, --foreign key
+ equip_id INTEGER REFERENCES equipment ON DELETE SET NULL, --foreign key
forces force_category
);
diff --git a/Project/part2.sql b/Project/part2.sql
new file mode 100644
index 0000000..066bc64
--- /dev/null
+++ b/Project/part2.sql
@@ -0,0 +1,253 @@
+-- Data normalization
+-- Step 1: `employee_base`
+CREATE TABLE employee_base (
+ emp_id INTEGER NOT NULL REFERENCES employee ON DELETE CASCADE,
+ base_id INTEGER NOT NULL REFERENCES base ON DELETE SET NULL,
+ PRIMARY KEY (emp_id, base_id)
+);
+-- Step 2: Migrate existing data (if `base_id` column in `employee` is populated).. миграция данных из employee
+INSERT INTO employee_base (emp_id, base_id)
+SELECT emp_id, base_id
+FROM employee
+WHERE base_id IS NOT NULL;
+-- Step 3: Remove the `base_id` column from the `employee` table
+ALTER TABLE employee
+DROP COLUMN base_id;
+-- проверка если миграция успешна пошла
+SELECT * FROM employee
+LIMIT 2;
+
+-- VIEWS
+CREATE VIEW employee_details AS -- вернет список сотрудников вместе с информацией о связанных с ними должностях (имя, зарплата и т.д.).
+SELECT
+ e.emp_id,
+ e.name AS employee_name,
+ e.surname,
+ e.date_of_birth,
+ e.education,
+ e.hiring_date,
+ p.name AS position_name,
+ p.salary_rub,
+ p.rank
+FROM employee e
+JOIN position p ON e.pos_id = p.pos_id;
+--bпровепка
+SELECT * FROM employee_details
+WHERE salary_rub > 80000
+ORDER BY salary_rub
+DESC
+LIMIT 5;
+
+CREATE VIEW mission_summary AS --вернет краткую информацию о каждой миссии, связанном с ней названии кампании, клиенте и используемом транспорте (если таковой имеется).
+SELECT
+ m.miss_id,
+ m.start_date_and_time,
+ m.end_date_and_time,
+ c.name AS campaign_name,
+ c.customer,
+ t.name AS transport_name
+FROM
+ mission m
+JOIN
+ campaign c ON m.camp_id = c.camp_id
+LEFT JOIN
+ missions_transport mt ON m.miss_id = mt.miss_id
+LEFT JOIN
+ transport t ON mt.trans_id = t.trans_id;
+-- ПРОВЕРКА
+SELECT * FROM mission_summary
+LIMIT 5;
+
+-- MATERIALIZED VIEW
+CREATE MATERIALIZED VIEW campaign_profit AS --сохраняет результат запроса, который вычисляет прибыль от каждой кампании (доходы - расходы).
+SELECT
+ camp_id,
+ name,
+ customer,
+ earning,
+ spending,
+ earning - spending AS profit
+FROM campaign;
+--обновляет данные в материализованном представлении campaign_profit.
+REFRESH MATERIALIZED VIEW campaign_profit;
+-- Проверка
+SELECT * FROM campaign_profit
+ORDER BY profit
+DESC
+LIMIT 2;
+
+-- CTE
+WITH employee_health_summary AS ( -- извлекает основные медицинские данные (рост, вес, группа крови) из таблиц employee и medical_card, объединяя их с помощью emp_id.
+ SELECT
+ e.emp_id,
+ e.name,
+ e.surname,
+ m.height_cm,
+ m.weight_kg,
+ m.diseases,
+ m.gender,
+ m.blood
+ FROM employee e
+ JOIN medical_card m ON e.emp_id = m.emp_id
+)
+SELECT
+ name,
+ surname,
+ height_cm,
+ weight_kg,
+ blood,
+ diseases,
+ gender,
+ CASE
+ WHEN height_cm < 160 THEN 'Short'
+ WHEN height_cm BETWEEN 160 AND 180 THEN 'Average'
+ WHEN height_cm > 180 THEN 'Tall'
+ END AS height_category,
+ CASE
+ WHEN weight_kg < 60 THEN 'Underweight'
+ WHEN weight_kg BETWEEN 60 AND 150 THEN 'Normal weight'
+ WHEN weight_kg > 150 THEN 'Overweight'
+ END AS weight_category
+FROM employee_health_summary;
+
+WITH transport_availability AS ( -- возвращает список названий транспортных средств со статусом их доступности
+ SELECT
+ t.trans_id,
+ t.name AS transport_name,
+ t.status,
+ m.start_date_and_time,
+ CURRENT_TIMESTAMP AS "current_time"
+ FROM transport t
+ LEFT JOIN missions_transport mt ON t.trans_id = mt.trans_id
+ LEFT JOIN mission m ON mt.miss_id = m.miss_id
+)
+SELECT
+ transport_name,
+ CASE
+ WHEN status = 'OUT_OF_USE' OR status = 'NOT_MAINTAINED' THEN 'Not Available'
+ WHEN start_date_and_time > CURRENT_TIMESTAMP THEN 'Available'
+ ELSE 'In Use'
+ END AS availability_status
+FROM transport_availability;
+
+-- TEMP_TABLE
+CREATE TEMPORARY TABLE temp_employee_availability AS -- Временная таблица для проверки доступности сотрудников в зависимости от их назначенных заданий. Может использоваться для просмотра того, кто может быть назначен на новое задание.
+SELECT
+ e.emp_id,
+ e.name AS employee_name,
+ e.surname,
+ CASE
+ WHEN m.miss_id IS NULL THEN 'Available'
+ ELSE 'Not Available'
+ END AS availability_status
+FROM employee e
+LEFT JOIN missions_emp me ON e.emp_id = me.emp_id
+LEFT JOIN mission m ON me.miss_id = m.miss_id
+WHERE m.end_date_and_time <= CURRENT_TIMESTAMP OR m.miss_id IS NULL;
+-- проверка
+SELECT * FROM temp_employee_availability
+LIMIT 5;
+
+-- RECURSIVE
+WITH RECURSIVE employee_mission_hierarchy AS ( --извлекает все задания, назначенные конкретному сотруднику (начиная с emp_id сотрудника = 1).
+ -- Base case: Start from a specific employee
+ SELECT
+ e.emp_id,
+ e.name AS employee_name,
+ e.surname AS employee_surname,
+ m.miss_id,
+ m.start_date_and_time,
+ m.end_date_and_time
+ FROM employee e
+ JOIN missions_emp me ON e.emp_id = me.emp_id
+ JOIN mission m ON me.miss_id = m.miss_id
+ WHERE e.emp_id = 1 -- Start with an employee (e.g., employee_id = 1)
+ UNION ALL
+ -- Recursive case: Find all missions this employee was assigned to
+ SELECT
+ e.emp_id,
+ e.name AS employee_name,
+ e.surname AS employee_surname,
+ m.miss_id,
+ m.start_date_and_time,
+ m.end_date_and_time
+ FROM employee e
+ JOIN missions_emp me ON e.emp_id = me.emp_id
+ JOIN mission m ON me.miss_id = m.miss_id
+ JOIN employee_mission_hierarchy emh ON m.miss_id = emh.miss_id -- Recursively find missions
+)
+SELECT
+ employee_name,
+ employee_surname,
+ miss_id,
+ start_date_and_time,
+ end_date_and_time
+FROM employee_mission_hierarchy;
+
+WITH RECURSIVE weapon_mission_path AS ( -- отслеживает использование определенного оружия (начиная с weapon_id = 1) в миссиях.
+ -- Base case: Start from a specific weapon
+ SELECT
+ w.weapon_id,
+ w.name AS weapon_name,
+ m.miss_id,
+ m.start_date_and_time,
+ m.end_date_and_time
+ FROM weapon w
+ JOIN equip_weapon ew ON w.weapon_id = ew.weapon_id
+ JOIN missions_emp me ON ew.equip_id = me.emp_id
+ JOIN mission m ON me.miss_id = m.miss_id
+ WHERE w.weapon_id = 1 -- For example, start from a specific weapon
+ UNION ALL
+ -- Recursive case: Find the next mission where this weapon is used
+ SELECT
+ w.weapon_id,
+ w.name AS weapon_name,
+ m.miss_id,
+ m.start_date_and_time,
+ m.end_date_and_time
+ FROM weapon w
+ JOIN equip_weapon ew ON w.weapon_id = ew.weapon_id
+ JOIN missions_emp me ON ew.equip_id = me.emp_id
+ JOIN mission m ON me.miss_id = m.miss_id
+ JOIN weapon_mission_path wmp ON m.miss_id = wmp.miss_id -- Recursively find related missions
+)
+SELECT
+ weapon_name,
+ miss_id,
+ start_date_and_time,
+ end_date_and_time
+FROM weapon_mission_path;
+
+-- INDEXES
+CREATE INDEX idx_employee_base_emp_id ON employee_base USING HASH(emp_id); --hash index
+CREATE INDEX idx_employee_base_base_id ON employee_base USING HASH(base_id);
+CREATE INDEX idx_employee_pos_id ON employee USING HASH(pos_id);
+CREATE INDEX idx_employee_emp_id ON employee USING HASH(emp_id);
+CREATE INDEX idx_employee_emp_name ON employee(name); --b-tree index by default
+CREATE INDEX idx_employee_emp_surname ON employee(surname);
+CREATE INDEX idx_position_pos_id ON position USING HASH(pos_id);
+CREATE INDEX idx_mission_camp_id ON mission USING HASH(camp_id);
+CREATE INDEX idx_mission_start_date ON mission(start_date_and_time);
+CREATE INDEX idx_mission_end_date ON mission(end_date_and_time);
+CREATE INDEX idx_mission_miss_id ON mission USING HASH(miss_id);
+CREATE INDEX idx_campaign_camp_id ON campaign USING HASH(camp_id);
+CREATE INDEX idx_missions_transport_miss_id ON missions_transport USING HASH(miss_id);
+CREATE INDEX idx_transport_trans_id ON transport USING HASH(trans_id);
+CREATE INDEX idx_medical_card_emp_id ON medical_card USING HASH(emp_id);
+CREATE INDEX idx_equip_weapon_weapon_id ON equip_weapon USING HASH(weapon_id);
+CREATE INDEX idx_employee_weapon_name ON weapon(name);
+
+--EXPLAIN ANALYZE
+EXPLAIN ANALYZE SELECT * FROM employee_details
+WHERE salary_rub > 80000
+ORDER BY salary_rub
+DESC
+LIMIT 5;
+
+-- index usage per table//отслеживает использование определенного оружия (начиная с weapon_id = 1) в миссиях.
+SELECT relname , indexrelname , idx_scan , idx_tup_read , idx_tup_fetch
+FROM pg_stat_user_indexes
+WHERE schemaname = 'public' and
+ relname in ('campaign');
+
+VACUUM;