Problem with database design for Hotel Booking [closed] - sql

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 3 years ago.
Improve this question
I am currently designing (as an assignment for the course at the university) a database for online booking of hotels worldwide and I have stumbled into a problem.
Before describing it, here are the tables of the relational model so far :
GUEST
guest_ID varchar PK
email varchar
guest_password varchar
first_name varchar
last_name varchar
mobile_num varchar
member_status varchar
pref_language varchar
pref_currency_code varchar
HOTEL
hotel_ID varchar PK
hotel_name varchar
ratings_avg int
phone_num varchar
email varchar
currency_code varchar
street_name varchar
street_num varchar
zip_code varchar
city varchar
country varchar
ROOM
room_ID varchar PK
hotel_ID varchar FK to Hotel
room_name varchar
low_season_rate numeric
high_season_rate numeric
max_persons int
BOOKING
guest_ID varchar FK to Guest
room_ID varchar FK to Room
check_in date
check_out date
(a combination of the first 4 as PK)
persons_num int
PAYMENT
guest_ID varchar FK to Guest
room_ID varchar FK to Room
date_paid timestamp
amount numeric
EVALUATION
guest_ID varchar FK to Guest
hotel_ID varchar FK to Hotel
eval_date date
(a combination of the first 3 as PK)
rating int
guest_comment text
I came up with this design thinking as follows:
The guests will book rooms, which belong to hotels, pay for the rooms and then, if they want, after their stay, evaluate the hotel.
So I considered Booking and Payment as relations between the Guest and the Room and the Evaluation as a relation between the Guest and the Hotel.
The problem this design seems to have is that the Payment and Evaluation are completely cut off from the Booking, so their tables can fill even without a preexisting booking having taken place.
And the way I see it now, a Guest pays for a Stay(=Booking) in a Room and evaluates a Stay(=Booking) in a Hotel, so I am thinking that these tables should refer to the Booking table.
But Booking is a relation, could I form a relation between an entity and another relation? Or is there another solution that I am missing?
I would welcome any thought about the subject.

First, your Payment and Evaluation are not "cut off" from Booking. You can make the relation across more than just one join. Secondly, remember there is an application on top of the database that will enforce some logic, such as not making bookings without a guest and not making guests without a booking.
If for some reason your requirements dictate that you enforce everything strictly in the database with keys, constraints, and triggers you will need to work on your schema a bit. I have a few suggestions on that below:
I like identity keys on my tables so that the database doesn't have to enforce combo key relations, I do this in the application layer (it gives me more freedom to make unexpected changes to schema and application later on).
You may want to take the rates out of the ROOM table. If they are updated, they are no longer applicable to previous BOOKINGs for the same hotel and room.
Payment and Evaluation only need a direct relation to a BOOKING. You can't have either without an actual stay.
imo a unique BOOKING is a HOTEL and ROOM for date range, so BOOKING should have a fk to HOTEL and ROOM.
How you handle GUEST relating to BOOKING is a little tricky. GUESTs being able to have more than one BOOKING is expected (imo) so you could put a fk to GUEST on BOOKING so that a BOOKING is now unique to a HOTEL, ROOM, GUEST, and date range.
But, if a BOOKING can have more than 1 GUEST, you need to make a relational lookup. Just GUESTid and BOOKINGid, so you can have a many::many and still relationally connect GUESTs to BOOKINGs
As long as you can make relational connections across all of your tables with joins, they do not need to all be directly related to all of the others.

Related

Should I index a foreign key that is going to be updated often

I am trying to create a library relational database, in which there are two tables: users and books. The relationship is one to many:one. A user has many books, and one book is owned by only one user. I was thinking that the book table should have a foreign key column that references the user id.
However I encountered a problem if I want to get all of the books of a given user.
The only option is to query the books whose user id equals the given user id using join.
But if there are many books it will take a lot of time.
So one may suggest to index the foreign key column as a non clustered index. However a book-user combination will be updated often--you don't keep a book more than one day in this library. But I read that update an indexed column often is not the best practice.
So what should I do? What is the best solution for this case?
Best performance for bi-directions query should include a middle table to storage the relationships. Both of customer and book should have unique index
The middle table - borrowing_table
with column user_id and book_id You storage the information of both users and books index (id) on this table, so you can query the table by user_id and get which books have been borrowed by this individual, you also can get the users quick from the query by books_id.
You should have an index on book_id.
Your concern about "frequent" updates just doesn't apply in a library setting. Libraries work on the time frames of days and weeks. Databases work on the timeframes of milliseconds, seconds, and minutes. What might seem frequent in a library is rather rare from the perspective of a database.
That said, I would suggest an intermediate table, not because you have a 1-n relationship at any given point in time. Instead, you have a time-tiled relationship. So:
create table UserBooks (
UserBookId int, -- serial, auto_increment, identity, generated always
UserId int references Users(UserId),
BookId int references Books(BookId),
FromDate datetime,
ToDate datetime,
DueDate datetime,
OverdueFees numeric(20, 4)
. . .
);
In other words, "borrowing" deserves to be entity itself, because there is more information than just the book and the user.

Oracle SQL: Foreign key from three possible tables?

Take the following scenario:
CREATE TABLE customers (
cust_num INTEGER PRIMARY KEY,
cust_name VARCHAR(60) NOT NULL,
//other info
);
CREATE TABLE checking_account (
acc_num NUMBER(16) NOT NULL,
acc_type VARCHAR(8) NOT NULL,
//other info
);
CREATE TABLE savings_account (
acc_num NUMBER(16) NOT NULL,
acc_type VARCHAR(8) NOT NULL,
//other info
);
CREATE TABLE loan_account (
acc_num NUMBER(16) NOT NULL,
acc_type VARCHAR(8) NOT NULL,
//other info
);
CREATE TABLE has_account (
acc_num NUMBER(16) NOT NULL,
acc_type VARCHAR(8) NOT NULL,
cust_num INTEGER
);
More than one customer may have the same account and additionally, one customer may have multiple accounts. The account number in the has_account table may or may not be unique across accounts.
How could this be represented? I have tried to implement class table inheritance and concrete inheritance but I can't figure out how to allow one account number to be shared across multiple accounts. I have yet to find an example or explanation which makes this consideration. Could anybody give me an insight as to how to achieve this functionality or at least point me in the right direction? Any help is greatly appreciated
'customers' table is your primary table which should be linked with all 3 tables 'checking_account','savings_account' and 'loan_account'.In these 3 table there should be one column cust_num which will represent forign key.
So if customer has saving account and loan account then for this customer there is 2 row in customers table and one-one row in savings_account & loan_account table.
Customer all account info should be in has_account table where cust_num is forign key so you can easily find customer info with his account details via join on customer & has_account table.
If you want to know one customer has how many account then use count(cust_num) in your customers table.
Note - If you follow good DB design then you should have only one table called as 'cust_account' in which columns should be like acc_num,acc_code,acc_name etc and acc_type column should be updated with valid value like 'saving','loan' or 'checking'.
In your table structure acc_type column is given for all 3 account type tables which has no sense if you have different table for different account type.Remove this column if you are going to use seprate table for account type otherwise use one table with column acc_type.
Not a complete answer and too long for a comment but I thought I'd address some of your reasons why you have three separate tables:
"checking account doesn't have an interest rate"
This is a business rule and should not be implemented by a different table structure. Also, in times of higher interest rates it's certainly plausible for a checking account to earn interest. Business rules are usually much easier to change that data structures.
a loan account doesn't have a balance
Again, this is a business rule - but certainly a loan has a principle balance.
one account number may be shared across multiple account types ... account number would need to be a primary key in which case it couldn't be shared across accounts
One way to solve that is to use account number , account type as a "logical" compound primary key (note that in most DB systems there are benefits to using a sequence number as a "true" primary key that is independent of the actual record information. What if an account number changes for some reason?
If there are attributes of one account type that cannot feasibly stored in a "shared" data model, then you could model those as sub-tables:
|- 0:1 -- 0:1 CheckingAccount
Customer 1--* Account -|- 0:1 -- 0:1 SavingsAccount
|- 0:1 -- 0:1 LoanAccount
But you may find that you end up with similar problem that are more easily solved using business rules that separate data structures.
Create custReg table which have parent-child relationship of account types between column data. That column named accountID would be PK. As common attributes can easily be placed in single table.
Further tables with different attributes can be created and subsequently linked with theirs account ID at first-child level.
Then use hierarchical queries to access data between tables.

SQL Database Roomrate Approaches

I've developed a Hotel Management System some time ago. Difference is, that this system is used by several hotels and property owners who rent their homes in a single database. I can't just add prices to the roomtypes/accommodations as they might differ from one week or the other.
The approach i've used to overcome the issue of fixed stays (weekends, weeks, midweeks) for the mobile homes and the possibility to reserve hotelrooms (no-arrival days, minimum stays etc) is to store prices in a rate-table. Which is as follows:
tablename: Availability
int id
int roomTypeId
decimal rate
dateTime day
bit canArrive
int minimumStay
...
I am wondering, now the database is growing with more hotels and mobilehome's, if this approach is done properly or if there might be better ways instead of storing a rate for each roomtype and each date.
Sure!
It's important to note that, while rates can change daily, they usually don't (otherwise, any ads showing a rate would go rapidly obsolete - they could have been designed months before).
A simple, naive (first-iteration) design is as follows:
Hotel
=========
id -- autoincrement
name -- varchar(50)
contactInformation -- (address, phone, etc)
RoomType
==========
id -- autoincrement
description -- varchar(50)
HotelRoomTypeRate
==================
id -- autoincrement
hotelId -- fk reference to hotel.id
roomTypeId -- fk reference to roomType.id
rate -- decimal
effectiveOn -- date (this is 'business'/calendar day)
HotelRoom
===========
id -- autoincrement
hotelId -- fk reference to hotel.id
roomTypeId -- fk reference to roomType.id
status -- fk reference to status table, for things like 'under construction'
HotelCheckIn
==============
id -- autoincrement
hotelId -- fk reference to hotel.id
customerId -- fk reference to customer.id
hotelRoomId -- fk reference to hotelRoom.id
checkedInOn -- date (again, 'business'/calendar day)
HotelCheckOut
===============
id -- autoincrement
hotelCheckInId -- fk reference to hotelCheckIn.id
checkedOutOn -- date (again, 'business'/calendar day)
You would of course need to tweak this to suit your needs.

Database design for flagging system

I have a database which captures information relating to a patient for a medical practice. This information is spread across several tables:
Patient - For contact information
PatientMedicalHistory - For medical conditions unrelated to the current problem
PatientEpisode - Financial information for the current visit
PatientEpisodeReason - Stuff relating to why the patient is here today
I want to introduce a flag system, so that any messages will appear when bringing up the patient details. So for example, if the patient has had a heart attack previously this would need to be flagged (that info would be in PatientMedicalHistory).
My current approach is to set up a flag lookup table which defines the flag type, and the table/column that the flag is referring to and what the value would be in order to raise that flag:
CREATE TABLE FlagType
(
ID INT PRIMARY KEY IDENTITY,
TypeName NVARCHAR(300) NOT NULL,
Colour NVARCHAR(100) NOT NULL,
Urgency INT NOT NULL
)
CREATE TABLE Flag
(
ID INT PRIMARY KEY IDENTITY,
FlagTypeID INT NOT NULL REFERENCES FlagType(ID),
TableName NVARCHAR(300) NOT NULL,
FieldName NVARCHAR(300) NOT NULL,
FlagValue NVARCHAR(300) NOT NULL
)
This seemed all very well, but then trying to write either a) a stored procedure that doesn't resemble a mess or b) a LINQ query that doesn't kill performance seems difficult.
Is there any alternatives to this? The issue is that the flag could be defined on any column in any of the tables above. This totals about 80 columns in total.
You can add three fields to PatientMedicalHistory table: organ, disease, criticality.
When a patient comes in with a problem, you can pull patient history based on the same organ or disease presented in the current episode where the criticality meets a certain threshold. What you are doing here is classifying your patient history data so it relates to the current episode data.

I need help in designing a database

I am working on a hotel management system in asp.net and I have a problem with designing the database.
I have something like this:
two types of Guests :family and company
each type can have many members and every member has attributes
the reservation is made by a guest
I think I need to make 3 tables:
Guest: guest id primary key, Guest name, Member ID foreign key
Members: Member ID primary key, Name, address, ...
Reservation: Reservation ID primary key, guest ID foreign key, ...
My problem is that I don't know how to make relation between tables.
For example the guest is company and he makes a reservation for 5 members,
but after a month he wants to make another reservation for 8 members.
What should I make so that I can make a reservation second time without being obligated to make another guest ID?
Seems like the schema doesn't need to be much more complex than this, unless you also need to show where certain guests get their own room, etc. As I mentioned in my comment, I don't think there is anything that dictates that every guest must be a member, in which case I would just wipe out ReservationGuests and re-populate when the reservation gets updated. Who wants to write logic that tries to guess which of the original guests are actually still on the list?
CREATE TABLE dbo.Members
(
MemberID INT PRIMARY KEY,
-- ... name, address, etc.
);
CREATE TABLE dbo.Reservations
(
ReservationID INT PRIMARY KEY,
MemberID INT FOREIGN KEY REFERENCES dbo.Members(MemberID),
... other attributes such as dates
);
CREATE TABLE dbo.ReservationGuests
(
ReservationID INT FOREIGN KEY REFERENCES dbo.Reservations(ReservationID),
GuestName NVARCHAR(255),
... other guest attributes
);
The problem is that you are assuming that the guest has members. It doesn't- as you mention, this week I might travel with my spouse, next week I might travel with the whole family, the week after that I might travel alone. The reservation has members, and the set of members might be different for each reservation. Hope that helps.
well u will need separate table for guests so for the 1st time they came to hotel u have to register that guest on your system. and as you said maybe he will come again after one month so just u have to search his SSN (Social Security Number). if he already register you don't have to register him again.
and your reservation table should be separate. and you should issue Reservation ID for each booking. so u can separately identify fields.
as example
A company came and resisted 1st time his registration number is "101" and that time his Reservation ID is "555"
after one month he will come again. and your system have option that check whether he is already resisted or not. well after system notice he already resisted and just make new Reservation ID for new booking
CREATE TABLE Member
(
Id INT IDENTITY (1,1) PRIMARY KEY,
Name VARCHAR(256),
Address VARCHAR(512),
MemberTypeId INT --FK to MemberType.Id
)
CREATE TABLE MemberType
(
Id INT IDENTITY(1,1) PRIMARY KEY,
TypeDescription VARCHAR(128)
)
CREATE TABLE Reservation
(
Id INT IDENTITY(1,1) PRIMARY KEY,
MemberId INT --FK to Member.Id
)
CREATE TABLE ReservationList
(
ReservationId INT, --FK to Reservation.Id
MemberId INT --FK to Member.Id
--Both of these values can act as a composite key
--At minimum, they should be unique as a pair
)
The above schema is how I would create the database based on your description. The Reservation table merely acts as an overarching reservation, and can be made by the company member without having to actually include the company member in the reservation (company makes reservation, but only for its employees). Then, the ReservationList is the list of all the members that will be tied to each reservation.
Hopefully this helps :)