第十三天、范式与关系,连表查询和子查询

一、范式与关系


假设有一个名为employee的员工表,它有九个属性:id(员工编号)、name(员工名称)、mobile(电话)、zip(邮编)、province(省份)、city(城市)、district(区县)、deptNo(所属部门编号)、deptName(所属部门名称)、表总数据如下:

id name mobile zip province city district deptNo deptName
101 张三 13910000001 13910000002 100001 北京 北京 海淀区 D1 部门1
101 张三 13910000001 13910000002 100001 北京 北京 海淀区 D2 部门2
102 李四 13910000003 200001 上海 上海 静安区 D3 部门3
103 王五 13910000004 510001 广东省 广州 白云区 D4 部门4
103 王五 13910000004 510001 广东省 广州 白云区 D5 部门 5

由于此员工表是非规范化的,我们将面对如下的问题。

  • 修改异常:上表中张三有两条记录,因为他隶属于两个部门。如果我们要修改张三的地址,必修修改两行记录。假如一个部门得到了张三的新地址并进行了更新,而另一个部门没有,那么此时张三在表中会存在两个不同的地址,导致了数据不一致
  • 新增异常: 假如一个新员工假如公司,他正处于入职培训阶段,还没有被正式分配到某个部门,如果deptNo字段不允许为空,我们就无法向employee表中新增该员工的数据。
  • 删除异常: 假设公司撤销了D3部门,那么在删除deptNo为D3的行时,会将李四的信息也一并删除。因为他隶属于D3这一部门。

第一范式(1NF)

表中的列只能含有原子性(不可再分)的值。

表中的张三有两个手机号存储在mobile列中,违反了 1NF 规则。为了使表满足 1NF,数据应该修改如下:

id name mobile zip province city district deptNo deptName
101 张三 13910000001 100001 北京 北京 海淀区 D1 部门1
101 张三 13910000002 100001 北京 北京 海淀区 D1 部门1
101 张三 13910000001 100001 北京 北京 海淀区 D2 部门2
101 张三 13910000002 100001 北京 北京 海淀区 D2 部门2
102 李四 13910000003 200001 上海 上海 静安区 D3 部门3
103 王五 13910000004 510001 广东省 广州 白云区 D4 部门4
103 王五 13910000004 510001 广东省 广州 白云区 D5 部门 5

第二范式(2NF)

第二范式要同时满足下面两个条件

  • 满足第一范式
  • 没有部分依赖

例如,员工表的一个候选键是{id,mobile,deptNo},而deptName依赖于deptNo,同样 name 依赖于 id,因此不是 2NF的。为了满足第二范式的条件,需要将这个表拆分成employee、dept、employee_dept、employee_mobile四个表。如下:

员工表 employee

id name zip province city district
101 张三 100001 北京 北京 海淀区
102 李四 200001 上海 上海 静安区
103 王五 510001 广东省 广州 白云区

部门表 dept

deptNo deptName
D1 部门1
D2 部门2
D3 部门3
D4 部门4
D5 部门5

员工部门关系表 employee_dept

id deptNo
101 D1
101 D2
102 D3
103 D4
104 D5

员工电话表 employee_mobile

id mobile
101 13910000001
101 13910000002
102 13910000003
103 13910000004

第三范式(3NF)

第三范式要同时满足下面两个条件

  • 满足第二范式
  • 没有传递依赖

例如,员工表的province、city、district依赖于zip,而zip依赖于id,换句话说,province、city、district传递依赖于id,违反了 3NF 规则。为了满足第三范式的条件,可以将这个表拆分成employee和zip两个表,如下

employee

id name zip
101 张三 100001
102 李四 200001
103 王五 510001

地区表area

zip province city district
100001 北京 北京 海淀区
200001 上海 上海 静安区
51000 广东省 广州 白云区

在关系数据库模型设计中,一般需要满足第三范式的要求。如果一个表具有良好的主外键设计,就应该是满足3NF的表。规范化带来的好处是通过减少数据冗余提高更新数据的效率,同时保证数据完整性。然而,我们在实际应用中也要防止过度规范化的问题。规范化程度越高,划分的表就越多,在查询数据时越有可能使用表连接操作。而如果连接的表过多,会影响查询性能。关键的问题是要依据业务需求,仔细权衡数据查询和数据更新关系,指定最合适的规范化程度。不要为了遵循严格的规范化规则而修改业务需求

数据库一对一、一对多、多对多设计


数据库实体间有三种对应关系:一对一、一对多、多对多

一对一关系示例:

一个学生对应一个学生档案材料 每个人都有唯一的身份证号

一对多关系示例:

一个学生只属于一个班,但这个班有多名学生

多对多关系示例:

一个学生可以选择多门课,一门课也可以有多名学生

一个人可以有多个角色,一个角色可以有多个人

关系

  • 创建成绩表scores,结构如下

    • id
    • 学生
    • 科目
    • 成绩

思考:学生列应该存什么信息呢?

答:学生列的数据不是在这里新建的,而应该从学生表引用过来,关系也是一条数据;根据范式要求应该存储学生的编号,而不是学生的姓名等其它信息

同理,科目表也是关系列,引用科目表中的数据

创建表的语句如下

create table scores(
id int primary key auto_increment,
stuid int,
subid int,
score decimal(5,2)
);

外键

思考:怎么保证关系列数据的有效性呢?任何整数都可以吗?
答:必须是学生表中id列存在的数据,可以通过外键约束进行数据的有效性验证
为stuid添加外键约束

alter table scores add constraint stu_sco foreign key(stuid) references students(id);

此时插入或者修改数据时,如果stuid的值在students表中不存在则会报错

在创建表时可以直接创建约束

create table scores(
id int primary key auto_increment,
stuid int,
subid int,
score decimal(5,2),
foreign key(stuid) references students(id),
foreign key(subid) references subjects(id)
);

外键的级联操作

  • 在删除students表的数据时,如果这个id值在scores中已经存在,则会抛异常
  • 推荐使用逻辑删除,还可以解决这个问题
  • 可以创建表时指定级联操作,也可以在创建表后再修改外键的级联操作
  • 语法
alter table scores add constraint stu_sco foreign key(stuid) references students(id) on delete cascade;

注:外键的添加会比较消耗性能

级联操作的类型包括:

  • restrict(限制):默认值,抛异常(常用)
  • cascade(级联):如果主表的记录删掉,则从表中相关联的记录都将被删除(一般不使用)
  • set null:将外键设置为空(一般不使用)
  • no action:什么都不做(一般不使用)

二、连表查询


  • 连接查询分类如下:

    • 表A inner join 表B:表A与表B匹配的行会出现在结果中
    • 表A left join 表B:表A与表B匹配的行会出现在结果中,外加表A中独有的数据,未对应的数据使用null填充
    • 表A right join 表B:表A与表B匹配的行会出现在结果中,外加表B中独有的数据,未对应的数据使用null填充
  • 在查询或条件中推荐使用“表名.列名”的语法

  • 如果多个表中列名不重复可以省略“表名.”部分

  • 如果表的名称太长,可以在表名后面使用' as 简写名'或' 简写名',为表起个临时的简写名称

练习

  • 查询学生的姓名、平均分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
group by students.sname;
  • 查询男生的姓名、总分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
where students.gender=1
group by students.sname;
  • 查询科目的名称、平均分
select subjects.stitle,avg(scores.score)
from scores
inner join subjects on scores.subid=subjects.id
group by subjects.stitle;
  • 查询未删除科目的名称、最高分、平均分
select subjects.stitle,avg(scores.score),max(scores.score)
from scores
inner join subjects on scores.subid=subjects.id
where subjects.isdelete=0
group by subjects.stitle;

三、子查询


  • 查询支持嵌套使用
  • 查询各学生的语文、数学、英语的成绩

什么是子查询

当一个查询是另一个查询的条件时,这个查询称之为子查询(内层查询)

什么时候用?

当查询需求比较复杂,一次性查询无法得到结果,需要多次查询时,

例如:给出一个部门名称,需要获得该部门所有的员工信息

分析:

1.需要先确定部门的id

2.然后才能通过id确定员工

解决问题的方式是把一个复杂的问题拆分为若干个简单的问题

2. 如何使用?

首先明确子查询就是一个普通的查询,当一个查询需要作为子查询使用时,用括号包裹即可

3. 需要注意

in中的子查询只能包含一个列

例如:查询财务部有哪些人

正确的写法:select name from emp where dept_id in (select id from dept where name = "财务");

错误的写法:select name from emp where dept_id in (select * from dept where name = "财务");

关键字:exists

exists后跟子查询,子查询有结果是为True,没有结果时为False。为True时外层执行,为False外层不执行

如何使用?

select from emp where exists (select from emp where salary > 1000);

前面 exists 后面 如果 后面 查询有结果时,前面 才会执行

今天特别累!

日期:2021/11/25

学习参考视频:*https://www.bilibili.com/video/BV1i7411G7kW?p=35&t=765.0

学习参考文档参考部分相关视频文案和课件,仅供个人学习和记录

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容

  • 数据库三范式 idnamemobilezipprovincecitydistrictdeptNodeptName1...
    _简_单_点_阅读 59评论 0 0
  • 示例表数据 假设有一个名为employee的员工表,它有九个属性:id(员工编号)、name(员工名称)、mobi...
    缓慢移动的蜗牛阅读 21,132评论 0 10
  • 1.数据约束 1.1默认值 作用:当用户对使用默认值的字段不插入值的时候,就使用默认值。 注意: ...
    ITSME_91b9阅读 305评论 0 1
  • 数据约束 对用户操作表的数据进行约束 默认值【default】作用: 当用户对使用默认值的字段不插入值的时候,就使...
    _Sisyphus阅读 217评论 0 0
  • 1.建表的语法 create table 表名( ); 注意:1.表名,字段名,关键字大小写忽略 2.创建一个用户...
    王炎鹏阅读 440评论 0 0