Hotel Room Booking System---数据库课程设计(数据库设计)

数据库设计
[应用系统设计]

课程题目需求

系统需求

The following data model is designed to hold information relating to a Hotel Room Booking System. For this scenario we need to define the following facts:
These facts define the requirements which the Database must meet and should be agreed between the Database User and the Database Designer prior to physical creation.
A local hotel needs a system that keeps track of its bookings (future, current and archived), rooms and guests. A room can be of a particular type and a particular price band. Room prices vary from a room to a room (depending on its type, available facilities, band, etc.) and from a season to a season (depending on the time of the year).
A room booking can include more than one room and more than one customer.
The draft facts have been defined as:
The Entities required should include:

  • Customer
  • Guest
  • Room
  • Booking
  • Payment
  • Room Type
  • Price Band
  • Room Facility

The Entities are related as follows:

  • A Customer can make one or many Bookings.
  • A Booking can be for one or many Guests - the Guest is not
    necessarily the person who makes the Booking.
  • A Room can be on one or many Bookings.
  • A Room may have many different Room Facilities.

需求分析

对题目的分析

  1. guest客人,指住房子的人;customer顾客,指预定的人
  2. 一个booking对应多个customer、guest、room
  3. 一个customer、guest、room对应多个booking
  4. 一个room对应多个payment(不同季节)、room_facility
  5. 一个price_band对应多个room(这里设计成1对1也行)
  6. 一个room_type对应多个room
  7. 一个booking_id唯一确定了一个预约订单,相当于预约订单的流水号

实体的属性

  1. 顾客customer(顾客customer_id,顾客名字customer_name,顾客联系方式customer_telephone)
  2. 客人guest(客人guest_id,客人名字guest_name,客人联系方式guest_telephone)
  3. 预定booking(唯一流水号booking_id,预定开始时间time_start,预约结束时间time_end,是否取消iscancel)
  4. 房间room(房间号room_id)
  5. 房间价格payment(价格payment,季节season)
  6. 房间价格区间price_band(下区间band_start,上区间band_end)
  7. 房间类型room_type(房间类型类型r_type)
  8. 房间设施room_facility(设施facility_id,设施名字facility_name)

实体间的联系

  1. 顾客customer与预定booking之间是n:m的联系
  2. 客人guest与预定booking之间是n:m的联系
  3. 预定booking与房间room之间是n:m的联系
  4. 房间room与房间价格payment之间是1:n的联系
  5. 房间room与房间价格区间price_band之间是n:1的联系
  6. 房间room与房间类型room_type之间是n:1的联系
  7. 房间room与房间设施room_facility之间是1:n的联系

数据库设计

概念设计

E-R图
E-R图设计如上。

PS: 画图软件使用的是Visio2013。

逻辑设计

E-R图中的实体和联系转换成关系表

customer(customer_id, customer_name, customer_telephone)

guest(guest_id, guest_name, guest_telephone)

bookings(booking_id, time_start, time_end , iscancel)

reserve (booking_id, customer_id)
foreign key (booking_id) references booking(booking_id)
foreign key (customer_id) references customer(customer_id)

booking_for (booking_id, guest_id)
foreign key (booking_id) references booking(booking_id)
foreign key (guest_id) references guest(guest_id)

room_types (r_type)

price_bands (band_start, band_end)

rooms(room_id, band_start, band_end, r_type)
foreign key (band_start, band_end) references price_band(band_start, band_end)
foreign key (r_type) references room_type(r_type)

payment(room_id, payment, season) (弱实体)
foreign key (room_id) references rooms(room_id)

room_facilities(facility_id, facility_name, room_id)
foreign key (room_id) references rooms(room_id)

booking_room (booking_id, room_id)
foreign key (booking_id) references booking(booking_id)
foreign key (room_id) references room(room_id)

数据库逻辑结构

表1.1 顾客customer基本信息表
属性名 数据类型 取值范围 是否是主属性或外键 完整性
customer_id int -231~231-1 Not null
customer_name varchar(10) Not null
customer_telephone varchar(15) Not null

PS:偷懒省略剩下10个

数据库实现

创建数据表

PS:所用到的数据库为MySQL8.0.18

按顺序创建如上数据库中的表
如果不按顺序创建,可能出现错误

  1. customer
  2. guest
  3. booking
  4. reserve
  5. booking_for
  6. price_band
  7. room_type
  8. room
  9. booking_room
  10. payment
  11. room_facility

如下为创建表的sql语句
加上drop table语句,方便以后调试

drop table if exists reserve;
drop table if exists customer;
drop table if exists booking_for;
drop table if exists room_facility;
drop table if exists guest;
drop table if exists booking_room;
drop table if exists payment;
drop table if exists room;
drop table if exists price_band;
drop table if exists room_type;
drop table if exists booking;

create table customer
(customer_id int,
 customer_name varchar(10) not null,
 customer_telephone varchar(15) not null,
 primary key (customer_id)
);

create table guest
(guest_id int,
 guest_name varchar(10) not null,
 guest_telephone varchar(15) not null,
 primary key (guest_id)
);

create table price_band
(band_start int not null check (band_start>0),
 band_end int not null check (band_end>0),
 primary key (band_start,band_end)
);

create table room_type
(r_type varchar(10) not null,
 primary key (r_type)
);

create table room
(room_id int,
 band_start int,
 band_end int,
 r_type varchar(10),
 primary key (room_id),
 foreign key(band_start,band_end) references price_band(band_start,band_end) on update cascade on delete set null,
 foreign key(r_type) references room_type(r_type) on update cascade on delete set null
);

create table room_facility
(facility_id int auto_increment,
 room_id int,
 facility_name varchar(10) not null,
 primary key(facility_id),
 foreign key(room_id) references room(room_id) on update cascade on delete set null
);

create table booking
(booking_id int auto_increment,
 time_start date not null,
 time_end date not null,
 iscancel varchar(6) check (iscancel in ('false', 'true')),
 primary key (booking_id)
);

create table reserve
(booking_id int,
 customer_id int,
 primary key (booking_id,customer_id),
 foreign key (booking_id) references booking(booking_id) on delete cascade on update cascade,
 foreign key (customer_id) references customer(customer_id) on delete cascade on update cascade
);

create table booking_room
(booking_id int,
 room_id int,
 primary key (booking_id,room_id),
 foreign key (booking_id) references booking(booking_id) on delete cascade on update cascade,
 foreign key (room_id) references room(room_id) on delete cascade on update cascade
);

create table booking_for
(booking_id int,
 guest_id int,
 primary key (booking_id,guest_id),
 foreign key (booking_id) references booking(booking_id) on delete cascade on update cascade,
 foreign key (guest_id) references guest(guest_id) on delete cascade on update cascade
);

create table payment
(room_id int,
 payment int check (payment>0),
 season varchar(6) check (season in ('fall', 'winter', 'spring', 'summer')),
 primary key (room_id,season),
 foreign key (room_id) references room(room_id) on delete cascade on update cascade
);

创建索引

#customer
create index customerNameIndex on customer(customer_name);
create index customerPhoneIndex on customer(customer_telephone);

#guest
create index guestNameIndex on guest(guest_name);
create index guestPhoneIndex on guest(guest_telephone);

#room
create index roomTypeIndex on room(r_type);

#payment
create index seasonIndex on payment(season);
create index paymentIndex on payment(payment);

创建初始数据

自己设计了一下初始数据

INSERT INTO customer(customer_id, customer_name,customer_telephone) VALUES (1, 'as','12345678910');
INSERT INTO customer(customer_id, customer_name,customer_telephone) VALUES (2, 'wq','14523698563');
INSERT INTO customer(customer_id, customer_name,customer_telephone) VALUES (3, 'wee','14785423695');
INSERT INTO customer(customer_id, customer_name,customer_telephone) VALUES (4, 'ty','95632452354');

INSERT INTO guest(guest_id, guest_name,guest_telephone) VALUES (1, 'as','12345678910');
INSERT INTO guest(guest_id, guest_name,guest_telephone) VALUES (2, 'wq','14523698563');
INSERT INTO guest(guest_id, guest_name,guest_telephone) VALUES (3, 'wee','14785423695');
INSERT INTO guest(guest_id, guest_name,guest_telephone) VALUES (4, 'hff','15233666554');

INSERT INTO price_band(band_start,band_end) VALUES (120,200);
INSERT INTO price_band(band_start,band_end) VALUES (111,250);
INSERT INTO price_band(band_start,band_end) VALUES (222,300);
INSERT INTO price_band(band_start,band_end) VALUES (400,500);


INSERT INTO room_type(r_type) VALUES ('normal');
INSERT INTO room_type(r_type) VALUES ('small');
INSERT INTO room_type(r_type) VALUES ('big');

INSERT INTO room(room_id,band_start,band_end,r_type) VALUES (101,120,200,'normal');
INSERT INTO room(room_id,band_start,band_end,r_type) VALUES (102,120,200,'normal');
INSERT INTO room(room_id,band_start,band_end,r_type) VALUES (201,111,250,'small');
INSERT INTO room(room_id,band_start,band_end,r_type) VALUES (301,222,300,'big');
INSERT INTO room(room_id,band_start,band_end,r_type) VALUES (401,400,500,'big');

INSERT INTO booking(booking_id, time_start,time_end,iscancel) VALUES (12233, '2019-12-16','2019-12-17','false');
INSERT INTO booking(booking_id, time_start,time_end,iscancel) VALUES (12345, '2019-12-15','2019-12-16','false');
INSERT INTO booking(booking_id, time_start,time_end,iscancel) VALUES (12444, '2019-12-17','2019-12-18','false');
INSERT INTO booking(booking_id, time_start,time_end,iscancel) VALUES (13333, '2019-12-20','2019-12-21','false');

INSERT INTO reserve(booking_id, customer_id) VALUES (12345, '1');
INSERT INTO reserve(booking_id, customer_id) VALUES (12345, '2');
INSERT INTO reserve(booking_id, customer_id) VALUES (12233, '3');
INSERT INTO reserve(booking_id, customer_id) VALUES (12444, '4');

INSERT INTO booking_for(booking_id, guest_id) VALUES (12345, '1');
INSERT INTO booking_for(booking_id, guest_id) VALUES (12345, '2');
INSERT INTO booking_for(booking_id, guest_id) VALUES (12233, '3');
INSERT INTO booking_for(booking_id, guest_id) VALUES (12444, '4');

INSERT INTO booking_room(booking_id, room_id) VALUES (12345, '101');
INSERT INTO booking_room(booking_id, room_id) VALUES (12345, '102');
INSERT INTO booking_room(booking_id, room_id) VALUES (12233, '201');
INSERT INTO booking_room(booking_id, room_id) VALUES (12444, '101');

INSERT INTO room_facility(room_id, facility_name) VALUES (101, '沙发');
INSERT INTO room_facility(room_id, facility_name) VALUES (101, '椅子');
INSERT INTO room_facility(room_id, facility_name) VALUES (102, '桌子');
INSERT INTO room_facility(room_id, facility_name) VALUES (201, '电视机');
INSERT INTO room_facility(room_id, facility_name) VALUES (null, '电视机');
INSERT INTO room_facility(room_id, facility_name) VALUES (null, '电视机');

INSERT INTO payment(room_id,payment,season) VALUES (101,120,'spring');
INSERT INTO payment(room_id,payment,season) VALUES (101,170,'summer');
INSERT INTO payment(room_id,payment,season) VALUES (101,200,'fall');
INSERT INTO payment(room_id,payment,season) VALUES (101,160,'winter');
INSERT INTO payment(room_id,payment,season) VALUES (102,120,'spring');
INSERT INTO payment(room_id,payment,season) VALUES (102,140,'summer');
INSERT INTO payment(room_id,payment,season) VALUES (102,200,'fall');
INSERT INTO payment(room_id,payment,season) VALUES (102,190,'winter');
INSERT INTO payment(room_id,payment,season) VALUES (201,111,'fall');
INSERT INTO payment(room_id,payment,season) VALUES (301,222,'spring');
INSERT INTO payment(room_id,payment,season) VALUES (401,400,'summer');
INSERT INTO payment(room_id,payment,season) VALUES (401,500,'fall');

添加触发器、函数、过程

触发器

由于MySQL创建触发器只能对于一个insert、update或delete操作。
所以此处需要复制粘贴一个

#price_band
#确保price_band_start 小于或等于 price_band_end
drop trigger if exists checkBands_1;
create TRIGGER checkBands_1
before insert #(update)
on price_band
for EACH ROW
begin
DECLARE
msg VARCHAR(50);
if new.band_end<new.band_start then
set msg = "价格区间错误.";
			SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = msg;
end if;
END;

以下触发器用于管理price_band表。
即用户不直接对price_band表进行操作,price_band表自动更新。

#payment---------------管理priceBand
#更新price_band数据
drop trigger if exists updatePriceBands_1;
create TRIGGER updatePriceBands_1
after insert
on payment
for each row
begin
	declare msg varchar(50);
	declare temp_payment int default 0;
	#该room新的band_start与band_end
	declare temp_bs int default 1000000;
	declare temp_be int default 0;
	#循环控制变量
	declare flag int default 0;
	#计数
	declare count_num int default 0;
	declare count_num2 int default 0;
	#该房间的旧值
	declare old_bs int default 0;
	declare old_be int default 0;
	#判断的值
	declare is_same int default 0;
	
	#获得最大值和最小值
	declare p_list cursor for
	select payment
	from payment
	where room_id = new.room_id;
	
	declare continue handler for not found set flag=1;
	
	OPEN p_list;
	fetch p_list into temp_payment;
	while flag <> 1 do
		IF temp_bs > temp_payment then
			set temp_bs = temp_payment;
		END IF;
		IF temp_be < temp_payment then
			set temp_be = temp_payment;
		END IF;
	fetch p_list into temp_payment;
	end while;
	
	#获得该房间的旧值
	select band_start,band_end
	into old_bs,old_be
	from room
	where room_id = new.room_id;
	
	#看看旧值与新值是否一样,一样is_same为1,不一样为0
	if old_bs = temp_bs and old_be = temp_be then
		set is_same = 1;
	else
		set is_same = 0;
	end if;
	
	#如果is_same=1什么都不做,如果is_same=0,需要进行操作
	if is_same = 0 then 
		#看看旧值的房间有几个
		select count(*)
		into count_num
		from room natural join price_band
		where old_bs = price_band.band_start and old_be = price_band.band_end;
		
		#看看新值的房间是否存在
		select count(*)
		into count_num2
		from room natural join price_band
		where temp_bs = price_band.band_start and temp_be = price_band.band_end;
		
		#如果新值存在,只更新room的priceBand,如果新值不存在,就进行如下操作
		if count_num2 = 0 then 
			#如果num=1,就进行更新操作
			if count_num = 1 then
				update price_band
				set band_start = temp_bs, band_end = temp_be
				where band_start = old_bs and band_end = old_be;
			else
				insert into price_band(band_start,band_end)
				values(temp_bs,temp_be);
			end if;
		end if;
		#更新room的band_start和band_end,有级联更新也可以不设置,但是以防null的现象
		update room
		set band_start = temp_bs, band_end = temp_be
		where room_id = new.room_id;
	end if;
end;

#drop trigger if exists updatePriceBands_2;
#create TRIGGER updatePriceBands_2


#room
#删除room的时候判断,当前band的数量,如果等于1就一并删除
drop trigger if exists deleteRoomBand_1;
create TRIGGER deleteRoomBand_1
before delete
on room
for each row
begin
	declare count_num int default 0;
	
	#看看band的数量
	select count(*)
	into count_num
	from room natural join price_band
	where old.band_start = price_band.band_start and old.band_end = price_band.band_end;
	
	if count_num = 1 then
		delete from price_band
		where band_start = old.band_start and band_end = old.band_end;
	end if;
end;

过程

#过程
#获得当前所有没有被预约的房间
drop procedure if exists getroomAvailable;
create PROCEDURE getRoomAvailable(in t_start DATE, in t_end DATE)
BEGIN
	select *
	from room
	where room_id not in (select room_id 
					 from booking_room natural join booking
					 where (time_start <= t_start and time_end >= t_start)
					 or ( time_start <= t_end and time_end >= t_end)
					 or (time_start >= t_start and time_end <= t_end));
end;

函数

#函数
#计算区间内的获得的利润
drop function if exists getIncome;
CREATE FUNCTION getIncome(t_start DATE, t_end DATE)
	RETURNS decimal(10,2)
    DETERMINISTIC
BEGIN
	DECLARE income NUMERIC(10,2) DEFAULT 0;
	
	DECLARE temp_season VARCHAR(6) default 'Spring';
	DECLARE temp_payment NUMERIC(10,2) DEFAULT 0;
	DECLARE temp_time_start DATE;
	DECLARE temp_time_end DATE;
	declare flag int default 0;
	
	DECLARE p_list cursor for
	select payment,season,time_start,time_end
	from booking_room NATURAL join booking NATURAL join payment
	where time_start >= t_start and time_end <= t_end;
	
			
	declare continue handler for not found set flag=1;
	 
	OPEN p_list;
	fetch p_list into temp_payment, temp_season, temp_time_start,temp_time_end;
	while flag <> 1 do
		IF QUARTER(temp_time_start) = 1 and temp_season = 'Spring' then
			set income = income + temp_payment;
		ELSEIF QUARTER(temp_time_start) = 2 and temp_season = 'Summer' then
			set income = income + temp_payment;
		ELSEIF QUARTER(temp_time_start) = 3 and temp_season = 'Fall' then
			set income = income + temp_payment;
		ELSEIF QUARTER(temp_time_start) = 4 and temp_season = 'Winter' then
			set income = income + temp_payment;
		END IF;
	fetch p_list into temp_payment, temp_season, temp_time_start,temp_time_end;
	end while;
	
	RETURN income;
END;

遇到的问题

结语

未完待续。。。

发布了1 篇原创文章 · 获赞 0 · 访问量 8

猜你喜欢

转载自blog.csdn.net/LittleSeedling/article/details/105319613
今日推荐