{"id":24991937,"url":"https://github.com/chechelnitskaya/pet-project-2","last_synced_at":"2025-07-12T12:43:18.054Z","repository":{"id":274075862,"uuid":"921832893","full_name":"chechelnitskaya/Pet-project-2","owner":"chechelnitskaya","description":"Моделирование СУБД для отеля и написание SQL-запросов к ней","archived":false,"fork":false,"pushed_at":"2025-01-24T18:56:37.000Z","size":294,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-04T13:53:02.704Z","etag":null,"topics":["database-management","erdiagram","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chechelnitskaya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-24T17:46:15.000Z","updated_at":"2025-01-24T18:57:46.000Z","dependencies_parsed_at":"2025-01-24T18:44:12.680Z","dependency_job_id":null,"html_url":"https://github.com/chechelnitskaya/Pet-project-2","commit_stats":null,"previous_names":["chechelnitskaya/pet-project-2"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chechelnitskaya%2FPet-project-2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chechelnitskaya%2FPet-project-2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chechelnitskaya%2FPet-project-2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chechelnitskaya%2FPet-project-2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chechelnitskaya","download_url":"https://codeload.github.com/chechelnitskaya/Pet-project-2/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246187238,"owners_count":20737463,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database-management","erdiagram","postgresql","sql"],"created_at":"2025-02-04T13:53:07.360Z","updated_at":"2025-03-29T13:15:52.404Z","avatar_url":"https://github.com/chechelnitskaya.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# База данных для отеля «Гранд Кисловодск»\n\nРоссийские курорты набирают популярность! Не исключение и прекрасный город Кисловодск и в частности - знаменитый отель Гранд Кисловодск, сервису которого позавидуют любые европейские гостиницы Будапешта, Праги, Рима, Осло … перечислять можно бесконечно!  \nТеперь с помощью таких систем управления базами данных, как PostgreSQL, отель сможет вывести свой менеджмент на новый уровень.  \nДалее опишем программу, которую мы предлагаем Гранд Кисловодску для более эффективного управления.  \n\n\n## Кому нужна разрабатываемая программа (категории пользователей)\n\nПрограмма предназначена для следующих категорий пользователей:\n\n- Администраторы — управление бронированиями и регистрацией гостей.\n- Управляющие — контроль работы отеля.\n- Персонал — обслуживание номеров и уборка.\n- Гости — просмотр доступных номеров, бронирование, проверка заказов.\n- Менеджеры — анализ данных для повышения продаж и разработки маркетинговых стратегий.\n\n## Функциональные требования\n\n### Регистрация и управление аккаунтами гостей\n\n- Добавление, изменение и удаление информации о гостях.\n- Хранение истории бронирований и отзывов.\n\n### Управление бронированиями\n\n- Создание, изменение и отмена бронирований.\n- Поиск доступных номеров по параметрам.\n- Подтверждение бронирований администраторами.\n\n### Управление номерами\n\n- Учет состояния номеров (свободен, занят, на уборке и т.д.).\n- Хранение информации о типах номеров и их характеристиках.\n- Управление заявками на уборку и ремонт.\n\n### Отчётность и аналитика\n\n- Генерация отчётов по загрузке, доходам и другим показателям.\n- Анализ статистики бронирований и отзывов.\n\n### Обратная связь\n\n- Оставление и просмотр отзывов.\n- Анализ отзывов менеджерами для улучшения качества обслуживания.\n\n## Структура базы данных\n\n### Сущности и атрибуты\n\n| Сущность      | Атрибуты                                                                 |\n|---------------|--------------------------------------------------------------------------|\n| Гости     | GuestID (PK), FullName, Email, PhoneNumber, DateOfBirth, RegistrationDate |\n| Номера    | RoomID (PK), RoomType, Capacity, Price, Status                           |\n| Бронирования | BookingID (PK), GuestID (FK), RoomID (FK), CheckInDate, CheckOutDate, BookingDate, Status |\n| Отзывы    | ReviewID (PK), GuestID (FK), RoomID (FK), Rating, Comment, ReviewDate   |\n| Персонал  | StaffID (PK), FullName, Position, PhoneNumber, Email                    |\n| Заявки    | RequestID (PK), RequestType, GuestID (FK), StaffID (FK), RoomID (FK), RequestDate, RequestStatus |\n\n### Связи между сущностями:\n\n- Гости могут иметь несколько бронирований, но каждое бронирование принадлежит только одному гостю (1:N).\n- Номера могут быть забронированы многими гостями (через бронирования), но каждое бронирование связано только с одним номером (1:N).\n- Гости могут оставить несколько отзывов, но каждый отзыв принадлежит только одному гостю (1:N).\n- Номера могут получить несколько отзывов, но каждый отзыв относится только к одному номеру (1:N).\n- Гости могут запросить какие-то услуги при желании, однако каждая заявка на услугу оформляется только на одного конкретного гостя (1:N).\n- За сотрудником может быть закреплено несколько заявок, либо ни одного, если у него выходной день, однако каждая заявка выполняется сотрудником единолично (1:N).\n\n### ER-диаграмма\n\n![Компьютер](photo_5395671688189962690_y.jpg)\n\n### Ограничения данных:\n- Email должен соответствовать формату электронной почты (к примеру, guest1@mail.com);\n- PhoneNumber также должен соответствовать международному стандарту номера телефона – + (код страны) (XXX) XXX-XX-XX;\n- DateOfBirth должна быть раньше даты заезда и соответствовать формату XX.XX.XXXX;\n- Capacity должно быть целым положительным числом;\n- Price – должно быть положительным числом;\n- Status для Rooms и Bookings должен находиться в одном из состояний: {“Свободен”, “Занят”};\n- Rating должен быть числом от 1 до 5;\n- Position должен принимать значения из списка должностей: {“Администратор”, “Уборщик”, “Повар”, “Ремонтник”, “Водитель”};\n- RequestType должен принимать значения из списка: {“Поломка”, “Уборка”, “Поездка”, “Пища”};\n- RequestStatus должна принимать значения из списка: {“Подана”; “В обработке”, “Выполнена”}.\n\n### Функциональные зависимости:\n\n- Guests:  \nGuestID =\u003e FullName, Email, PhoneNumber, DateOfBirth, RegistrationDate (GuestID определяет остальные атрибуты сущности Guests)  \n- Rooms:  \nRoomID =\u003e RoomType, Capacity, Price, Status (RoomID определяет тип номера, вместимость, цену и статус)  \n- Bookings:  \nBookingID =\u003e GuestID, RoomID, CheckInDate, CheckOutDate, BookingDate, Status (BookingID определяет ID гостя, ID комнаты, дату заезда и дату выезда, дату бронирования и статус)  \nGuestID, RoomID, CheckInDate =\u003e BookingID (комбинация ID гостя, ID комнаты и даты заезда определяет ID бронирования)  \n- Reviews:  \nReviewID =\u003e GuestID, RoomID, Rating, Comment, ReviewDate, CheckInDate, CheckOutDate (ReviewID определяет ID гостя, ID комнаты, оценку, комментарий, дату отзыва, дату выезда)  \nGuestID, RoomID, ReviewDate =\u003e ReviewID (комбинация из ID гостя, ID комнаты, даты отзыва определяет ID отзыва)  \n- Staff:  \nStaffID =\u003e FullName, Position, PhoneNumber, Email (StaffID определяет полное имя, должность, номер телефона и электронную почту сотрудника)  \n- Requests:\nRequestID =\u003e RequestType, GuestID, StaffID, RoomID, RequestDate, RequestStatus (RequestID определяет тип заявки, ID гостя, ID сотрудника, ID комнаты, дату заявки, статус заявки)  \n\n### Нормализация базы данных.\n- Гости (Guests):  \nGuestID (PK) – уникальный идентификатор гостя  \nFullName – полное имя  \nEmail – адрес электронной почты  \nPhoneNumber – номер телефона  \nDateOfBirth – дата рождения  \nRegistrationDate – дата регистрации в системе  \n\n- Номера (Rooms):  \nRoomID (PK) – уникальный идентификатор номера  \nRoomType – тип номера (одноместный, двухместный, люкс и т.д.)  \nCapacity – максимальная вместимость  \nPrice – цена за ночь  \nStatus – статус номера (свободен, занят, на уборке, на ремонте)  \n\n- Бронирования (Bookings):  \nBookingID (PK) – уникальный идентификатор бронирования  \nGuestID (FK) – ссылка на гостя  \nRoomID (FK) – ссылка на номер  \nCheckInDate – дата заезда  \nCheckOutDate – дата выезда  \nBookingDate – дата бронирования  \nStatus – статус бронирования (подтверждено, отменено)  \n\n- BookingInfo:  \nGuestID (FK) – ссылка на гостя  \nRoomID (FK) – ссылка на номер  \nCheckInDate – дата заезд  \nBookingID (FK) – уникальный идентификатор бронирования  \n\n- Отзывы (Reviews):  \nReviewID (PK) – уникальный идентификатор отзыва  \nGuestID (FK) – ссылка на гостя  \nRoomID (FK) – ссылка на номер  \nRating – оценка (1-5)  \nComment – текст отзыва  \nReviewDate – дата отзыва  \n\n- ReviewDetails:  \nGuestID (FK) – ссылка на гостя  \nRoomID (FK) – ссылка на номер  \nCheckInDate – дата заезда  \nCheckOutDate – дата выезда  \nReviewID (FK) – уникальный идентификатор отзыва  \n\n- Персонал (Staff):  \nStaffID (PK) – уникальный идентификатор сотрудника  \nFullName – полное имя  \nPosition – должность (администратор, управляющий, уборщик и т.д.)  \nPhoneNumber – номер телефона  \nEmail – адрес электронной почты  \n\n- Заявки (Requests):  \nRequestID - уникальный идентификатор заявки  \nRequestType - тип заявки (уборка/починка/другое)  \nGuestID (FK) - уникальный идентификатор гостя  \nStaffID (FK) – уникальный идентификатор сотрудника (если заявка на плановую уборку, например)  \nRoomID (FK) – уникальный идентификатор номера  \nRequestDate - дата подачи заявки  \nRequestStatus - статус заявки (подана/в обработке/в процессе/выполнена/отменена)  \n\n## Аномалии при недонормализованной базе.\n- Аномалия обновления.\nЕсли информация о датах заезда и выезда будет дублирована в таблице Reviews, то при изменении дат бронирования придется обновлять эту информацию во всех связанных отзывах. Это может привести к ошибкам.\n- Аномалия удаления.\nЕсли гость удалит все свои бронирования, то могут быть удалены и связанные с ним отзывы.\n- Избыток данных.\nВ таблице Bookings дублируется информация о датах заезда и выезда, которая также присутствует в таблице Reviews.\n\n## Примеры SQL-запросов\n\n### Создание таблиц в SQL:\n```sql\ncreate table Guests(\nGuestID INT primary key,\nFullName VARCHAR(100) not null,\nEmail VARCHAR(100) unique,\nPhoneNumber VARCHAR(20),\nDateOfBirth DATE,\nRegistrationDate DATE);\n\ncreate table Rooms(\nRoomID INT primary key,\nRoomType VARCHAR(100) not null,\nCapacity INT,\nPrice DECIMAL(10, 2) not null,\nStatus VARCHAR(100));\n\ncreate table Bookings(\nBookingID INT primary key,\nGuestID INT,\nRoomID INT,\nCheckInDate DATE,\nCheckOutDate DATE,\nBookingDate DATE,\nStatus VARCHAR(100),\nforeign key (GuestID) references Guests(GuestID),\nforeign key (RoomID) references Rooms(RoomID));\n\ncreate table BookingInfo(\nGuestID INT,\nRoomID INT,\nCheckInDate DATE,\nBookingID INT,\nforeign key (GuestID) references Guests(GuestID),\nforeign key (RoomID) references Rooms(RoomID),\nforeign key (BookingID) references Bookings(BookingID));\n\ncreate table Reviews(\nReviewID INT primary key,\nGuestID INT,\nRoomID INT,\nRating INT,\ncomment TEXT,\nReviewDate DATE,\nforeign key (GuestID) references Guests(GuestID),\nforeign key (RoomID) references Rooms(RoomID));\n\ncreate table ReviewDetails(\nGuestID INT,\nRoomID INT,\nCheckInDate DATE,\nCheckOutDate DATE,\nReviewID INT,\nforeign key (GuestID) references Guests(GuestID),\nforeign key (RoomID) references Rooms(RoomID),\nforeign key (ReviewID) references Reviews(ReviewID));\n\ncreate table Staff(\nStaffID INT primary key,\nFullName VARCHAR(100) not NULL,\nposition VARCHAR(100),\nPhoneNumber VARCHAR(25),\nEmail VARCHAR(100) UNIQUE);\n\ncreate table Requests(\nRequestID INT primary key,\nRequestType VARCHAR(50),\nGuestID INT,\nStaffID INT,\nRoomID INT,\nRequestDate DATE,\nRequestStatus VARCHAR(50),\nforeign key (GuestID) references  Guests(GuestID),\nforeign key (StaffID) references  Staff(StaffID),\nforeign key (RoomID) references  Rooms(RoomID));\n```\n\nПродемонстрируем, каким образом указанные в начале функциональные требования могут быть реализованы в созданной базе данных. Количество возможных запросов велико, однако для демонстрации напишем несколько различных запросов:\n\n### Добавление информации о госте:\n```sql\ninsert into Guests (GuestID, FullName, Email, PhoneNumber, DateOfBirth, RegistrationDate)\nvalues (1, 'Брейман Александр Давидович', 'breyman@gmail.com', '+ 7 (777) 777-77-77', '29.03.1972', current_date);\n```\n### Список свободных двухместных комнат, чтобы понимать, куда заселить новых гостей:\n```sql\nselect RoomID, Price from Rooms\nwhere RoomType = 'двухместный' and Status = 'свободен';\n```\n### Информация о всех гостях, которые останавливались в номере 13 (вдруг мы нашли золотую сережку под ковром в номере 13 и хотим перезвонить всех и найти гостя, который ее потерял?):\n```sql\nselect b.GuestID, b.CheckInDate, b.CheckOutDate, g.FullName, g.PhoneNumber\nfrom Bookings b\njoin Guests g on b.GuestID = g.GuestID\nwhere b.RoomID = 13;\n```\n### Представим, что мы хотим сделать акцию и предоставить скидку всем клиентам, которые останавливались у нас минимум 2 раза. Выведем их id, имена и почты, куда и направим информацию об акции:\n```sql\nselect g.GuestID, g.FullName, g.Email\nfrom Guests g\njoin BookingInfo b on g.GuestID = b.GuestID\ngroup by g.GuestID, g.FullName, g.Email\nhaving count(b.BookingID) \u003e 1;\n```\n### Допустим, менеджер хочет посмотреть, какие отзывы оставляли клиенты номеров, в которых убирался сотрудник с id 17:\n```sql\nselect r.ReviewID, r.comment\nfrom Reviews r\njoin Requests re on r.RoomID = re.RoomID\nwhere re.RequestType = 'уборка' and re.StaffID = 17;\n```\n### Проанализируем удовлетворенность гостей по средней оценке за 12 месяцев:\n```sql\nselect datepart(month, ReviewDate) MonthOfReview, avg(Rating) AverageRating\nfrom Reviews\nwhere ReviewDate \u003e= date_sub(current_date, interval 12 month)\ngroup by datepart(month, ReviewDate)\norder by datepart(month, ReviewDate);\n```\n### Посмотрим, какие сотрудники выполняли больше всего запросов (возможно, мы собираемся назначить им вознаграждение).  \nПонятно, что у нас есть сотрудники, которые не выполняют requests, так как их работа заключается в чем-то другом. Они нас сейчас не интересуют, но не обязательно их отфильтровывать в этом запросе, потому что они в любом случае окажутся внизу рейтинга и не помешают нашей задаче:\n```sql\nselect s.StaffID, s.FullName, s.position, count(r.RequestID) CountOfRequests\nfrom Staff s\nleft join Requests r on s.StaffID = r.StaffID\ngroup by s.StaffID, s.FullName, s.position\norder by count(r.RequestID) desc\nlimit 30;\n```\n### Допустим, мы хотим провести реновацию в отеле. Перед этим мы выведем список тех номеров, где чаще всего запрашивают ремонт. Их стоит проверить первыми — вероятно, эти номера больше всего нуждаются в реновации:\n```sql\nselect RoomID, count(RequestID) CountOfRequests\nfrom Requests\nwhere RequestType = 'починка'\ngroup by RoomID\norder by count(RequestID) desc\nlimit 50;\n```\n### Кроме того, в нашей базе данных потребуется группировка запросов в транзакции, чтобы никакая информация не потерялась из-за сбоя. Приведем пример группировки запросов в транзакции, который будет наиболее актуальным для нашей базы данных.\n\nЭто транзакция, которая обновляет информацию в таблицах с бронированием, комнатами и гостями. В противном случае (если не делать транзакции) может случиться так, что, например, в таблице с бронированиями бронь есть, а в таблице с комнатами написано, что комната свободна. \n```sql\nBEGIN\n\ninsert into Guests (GuestID, FullName, Email, PhoneNumber, DateOfBirth, RegistrationDate)\nvalues (1, 'Брейман Александр Давидович', 'breyman@gmail.com', '+ 7 (777) 777-77-77', '29.03.1972', '13.12.2024');\n\nupdate Rooms\nset Status = 'занят'\nwhere RoomID = 17;\n\ninsert into Bookings (BookingID, GuestID, RoomID, CheckInDate, CheckOutDate, BookingDate, Status)\nvalues (1, 1, 17, '27.12.2024'', '08.01.2025'', '13.12.2024', 'подтверждено');\n\ninsert into BookingInfo (GuestID, RoomID, CheckInDate, CheckOutDate, BookingID)\nvalues (1, 17, '27.12.2024', 1);\n\nCOMMIT;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchechelnitskaya%2Fpet-project-2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchechelnitskaya%2Fpet-project-2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchechelnitskaya%2Fpet-project-2/lists"}