数据库实验报告 设计酒店、员工、客户数据表 SQL Kingbase

版权声明:作者:cheese0_0,转载请注明出处来自https://blog.csdn.net/cheese0_0 商业转载请联系作者获得授权,非商业转载请注明出处 https://blog.csdn.net/cheese0_0/article/details/85058609

一、实验题目
已有条件:假设你创业的公司拥有多个酒店,每个酒店有酒店名、国家、城市、与最近机场的距离、星级等信息要登记,每个酒店有店长、店员、临时清洁工、临时厨师等员工要登记,针对每个客户分别记录了客户的ID、姓名、入住时间、退房时间、酒店名称等。
问题:请展开想象,按照关系数据库的要求设计酒店数据表、员工数据表、客户入住记录。
问题:请找出入住过所有酒店的客户ID和姓名,给出相应的关系代数表达式,给出相应的SQL查询语句。
二、相关原理与知识
(完成实验所用到的相关原理与知识)
1.定义模式
在SQL语句中模式定义语句如下:
CREATE SCHEMA <模式名>AUTHORIZATION<用户名>;
2.定义基本表
CREATE TABLE<表名> (<列名><数据类型> [列级完整性约束条件]
[,<列名><数据类型> [列级完整性约束条件]]

[,<表级完整性约束条件>]);
3.设置搜索模式路径
SET search_path TO “S-T”;
SET search_path TO PUBLIC;
SET search_path TO “S-T”,PUBLIC;
4.插入数据
插入单个元组--新元组插入指定表中。
语句格式:
INSERT
INTO <表名> [(<属性列1>[,<属性列2 >…)]
VALUES (<常量1> [,<常量2>] … ) ;
注:
INTO子句
指定要插入数据的表名及属性列
属性列的顺序可与表定义中的顺序不一致
没有指定属性列:表示要插入的是一条完整的元组,且属性列属性与表定义中的顺序一致
指定部分属性列:插入的元组在其余属性列上取空值
VALUES子句
提供的值的个数和值的类型必须与INTO子句匹配
5.数据查询
SELECT [ALL | DISTINCT] <目标列表达式> [,<目标列表达式>] …
FROM <表名或视图名>[, <表名或视图名> ] …
[ WHERE <条件表达式> ]
[ GROUP BY <列名1> [ HAVING <条件表达式> ] ]
[ ORDER BY <列名2> [ ASC | DESC ] ] ;
注:
SELECT子句:指定要显示的属性列;
FROM子句:指定查询对象(基本表或视图);
WHERE子句:指定查询条件;
GROUP BY子句:对查询结果按指定列的值分组,该属性列值相等的元组为一个组。通常会在每组中使用集函数;
HAVING短语:筛选出只有满足指定条件的组;
ORDER BY子句:对查询结果按指定列值升序或降序排序。
三、实验过程
(清晰展示实际操作过程,相关截图及解释)
建立以HOTEL命名的模式;
建立如下三个表:
HOTEL表:HOTEL(Hname,Hcountry,Hcity,Hdistanc,Hrank),用来存放酒店名称、所在国家、城市、距最近机场的距离和星级,在这里我假设每个酒店名字不一样,所以直接将酒店名称作为主码,即Hname为主码;
STAFF表:STAFF(Smanager,Sclerk,Scook,Scleaner,Hname),用来存放店长、店员、临时厨师、临时清洁工和所在酒店名称,又因为每个酒店的店长不一定完全不同,所以主码由店长和酒店名称这两个属性组成,PRIMARY KEY(Hname,Smanager),另外,注意Hname为外码,参照表为HOTEL。
CUSTOMER表:CUSTOMER(Cno,Cname,Cin,Cout,Hname),用来存放客户的ID、姓名、入住时间、退房时间、酒店名称。在这里,我把Cno与Cin这两个属性组合设置为主码,PRIMARY KEY(Cno,Cin)。因为如果单设Cno,那么一个客户只能在连锁酒店中住一次;如果Cno组合Hname,那么客户在每个酒店中都只能住一次;如果单设Cin或Cout,那么每个酒店同一天只能接受一位客户入住或退房,这些都是不符合实际的。本题中,需要满足不同客户在不同酒店都可以入住不止一次,同一酒店在同一天中也可以接纳多位用户入住或退房。对待这样的问题,可以选择不设主码,但是我的做法是把Cno客户ID与Cin入住时间组合作为主码,因为正常情况下同一用户ID在同一天只会入住一家酒店,这样既可以满足实际需求,某种程度上还起到预防身份信息盗用的作用。另外,注意Hname为外码,参照表为HOTEL。
建立模式和表后可以得到如下目录:
在这里插入图片描述
实验并没有要求向表中插入数据,但是为了使后面查询效果明显,在这里,需要发挥想象向HOTEL表和CUSTOMER表中插入数据。其中,为了迎合第二问查询的要求,必须存在入住了所有酒店的客户。
插入数据后的表如下所示:
在这里插入图片描述
在这里插入图片描述

找出入住过所有酒店的客户ID和姓名,给出相应的关系代数表达式,给出相应的SQL查询语句。
“住过所有酒店的客户”,这句话的逻辑关系可以等价为“没有酒店他没有住过”,关系代数表达式如下:
在这里插入图片描述
我们容易知道酒店的数目,因此只需将在不同酒店的住房记录条数等于酒店数目的客户输出即可。
因此,首先分析如何输出客户ID在不同酒店的住房记录,可以查询Cno与Hname,并使用DISTINCT去除重复项。

SELECT DISTINCT Cno,Hname 
 FROM customer

语句得到的结果如下:
在这里插入图片描述
此时,已经排除了有客户多次在同一家酒店居住的情况,表中的信息只是哪个用户曾在哪个酒店住过,不再含有次数或者其他干扰因素。
接下来查询上表中的记录数等于酒店数目的客户ID,即曾住过的酒店数与酒店总数相等的客户ID 。

SELECT DISTINCT Cno
FROM
 (
SELECT DISTINCT Cno,Hname
FROM customer
)
GROUP BY Cno
HAVING COUNT(*)=3

最后在外层查询里获得题目要求我们得到的Cno和Cname。
四、实验结果与分析
实验结果已在实验过程中给出。
本次实验我为我假想的创业公司旗下的三个连锁酒店建立了管理体系,由三个表构成,分别为HOTEL表、STAFF表和CUSTOMER表,其中customer表的主码需要额外注意,不能简单地用客户ID或者客户ID与酒店的组合作为主码,需要分析设置主码不同带来的影响,选择最符合实际的方式,譬如本次实验我用客户ID与入住时间的组合作为主码。然后发挥想象向所需表格中插入数据。至此为止,操作的流程与内容与前两次试验基本一致。
然后进入到第二问查询入住过所有酒店的客户ID和姓名。“住过所有酒店的客户”这句话与课本中的例子“选修了全部课程的学生”相似,所以我们容易得到这句话的逻辑关系可以等价为“没有酒店他没有住过”。SQL查询语句本想也套用课本中的例子,但是建表的方式略有不同,所以我想另辟蹊径。既然是我自己的酒店我会很容易知道数目,因此我认为只需将在不同酒店的住房记录条数等于酒店数目的客户输出即可得到题目要求的信息。由于存在同一客户入住过不同的酒店的情况,所以我使用使用DISTINCT来去除重复项。再利用嵌套查询即可获得住过所有酒店的客户ID和姓名。
五、问题总结
(记录所遇到的问题及解决方法)
1.customer表的主码问题
遇到问题:最初设定customer表时没有注意主码的选择,想当然的设置为客户ID,于是出现同一客户只能在连锁酒店中有一条入住信息。
解决方法:不设主码或将主码设置为客户ID与入住时间的组合。
2.查询语句
遇到问题1:刚开始我打算套用与课本相似的一个例子“没有一门课程是他没选的”,在这里正好可以改成“没有一个酒店是他没住过的”,利用多层嵌套解决问题。后来发现语句运行成功但是结果不正确,原因我推测是出在建表方式不同,
遇到问题2:
起初的代码如下:

SELECT Cno
FROM CUSTOMER
GROUP BY Cno
HAVING COUNT(*)=3

上述查询语句是将同一客户的入住记录条数与酒店数(3个)比较,当入住记录达到三条时,输出客户ID和姓名。这不仅无法直接输出客户姓名,更是没有考虑到一个客户可以在同一家酒店多次居住的情况。这段查询语句会把多次居住的情况与不同酒店居住的情况混在一起,造成干扰导致结果可能会不准确。
解决方法:
经过修改,SQL语句如下:

SELECT DISTINCT Cno,Cname
FROM CUSTOMER
where Cno in
(
SELECT DISTINCT Cno
FROM
 (
SELECT DISTINCT Cno,Hname
FROM customer
)
GROUP BY Cno
HAVING COUNT(*)=3
);

这一次我使用嵌套查询,子查询中先将入住所有酒店的客户ID输出,父查询再将用户姓名补充。
其中使用DISTINCT去除重复项,SELECT DISTINCT Cno,Hname FROM customer语句得到的结果如下:
在这里插入图片描述
从上图我们可以看到,004号客户在AB酒店居住两次的情况已视作重复,被“化简”为一次。因此,解决由同一客户多次居住同一酒店而引起的问题。
六、源代码
(源程序)
建立模式:

CREATE SCHEMA HOTEL

设计酒店数据表:

SET search_path TO HOTEL;
CREATE TABLE HOTELS
(Hname CHAR(9) PRIMARY KEY,
Hcountry CHAR(10),
Hcity CHAR(10),
Hdistance CHAR(15),
Hrank CHAR(2));

设计员工数据表:

SET search_path TO HOTEL;
CREATE TABLE STAFF
(Smanager CHAR(30),
Sclerk CHAR(40),
Scook CHAR(30),
Scleaner CHAR(30),
Hname CHAR(9),
PRIMARY KEY(Hname,Smanager),
FOREIGN KEY(Hname) REFERENCES HOTELS(Hname));

设计客户入住记录数据表:

SET search_path TO HOTEL;
CREATE TABLE customer
(Cno CHAR(9),
Cname CHAR(30),
Cin CHAR(15),
Cout CHAR(15),
Hname CHAR(9),
PRIMARY KEY(Cno,Cin),
FOREIGN KEY(Hname) REFERENCES HOTEL(Hname));

插入数据(部分):

INSERT INTO "HOTEL"."CUSTOMER"
 ("CNO","CNAME","CIN","COUT","HNAME" )
 VALUES 
 ('003','Hermione','2017.11.13','2017.11.17','AC' );

找出入住过所有酒店的客户ID和姓名查询语句:

    SELECT DISTINCT Cno,Cname
    FROM CUSTOMER
    where Cno in
    (
    SELECT DISTINCT Cno
    FROM 
    (
    SELECT DISTINCT Cno,Hname
    FROM customer
    )
    GROUP BY Cno
    HAVING COUNT(*)=3
    );

猜你喜欢

转载自blog.csdn.net/cheese0_0/article/details/85058609