04-数据库表设计三范式
1、表的设计范式
设计范式是设计表的依据,按照三范式设计的表不会出现数据的冗余
2、设计三范式
--第一范式:任何一张表都应该有主键,并且每一个字段原子性不可再分
不可再分表示该字段不应该可以自分一张表,例如学生和班级,如果放进一张表,班级这个字段还是可以再分成班级表,该表中有班级编号和班级名字,所以这些个字段不能放在一张表中,每个字段是原子性
一个表不能没有主键。
--第二范式:是在第一范式的基础上,所有非主键字段完全依赖一个主键字段,不能有部分依赖
例子:一张表中有学生编号sno,学生名sname,教师编号tno,教师名tname,该表中将字段sno和tno联合起来做一个复合主键,此时就有sname依赖sno,又有tname依赖tno,这时数据就冗余了
这种该怎么设计呢?
因为每一个学生有多名教师,每位教师又有多位学生,是多对多的关系
--所以多对多,三张表,其中关系表有两个外键约束
学生表
sno(pk) sname
------------------
1 张三
2 李四
3 王五
教师表
tno(pk) tname
----------------------
1 李老师
2 王老师
3 陈老师
教师与学生的关系表
id(pk) sno(fk) tno(fk)
---------------------------------------
1 1 2
2 1 3
3 2 1
4 2 2
5 2 3
....
--第三范式:在第二范式的基础上,所有非主键字段依赖主键,不能产生传递依赖
例如,学生和班级,一张表中,学号、姓名、班号、班名,此时仅将学号定为主键,此时班号依赖学号主键,但是班名却依赖班号,然而班号却不是主键,这是不行的。
一个班级有多名学生,这是一对多的关系
--所以这样设计,一对多,两张表,多的表加外键
班级t_class表
cno(pk) cname
--------------------
1 banji1
2 banji2
学生表t_student
sno(pk) sname cno(fk)
---------------------------------
1 zz 1
2 ss 2
3 ww 1
4 ee 2
--实际开发中,以客户需求为准,有时候会拿冗余换执行速度
3、一对一怎么设计?
一张用户表t_user一般有用户名和密码,当然还有其他信息,此时我们将这张大表拆分成两张表:
用户登录表t_ulogin:其中保存用户名和密码
用户详细信息表t_udetail:保存有用户名,住址等其他信息
这时有两种设计方案:
--主键共享
将t_udetail表的主键用t_ulogin表的主键约束
t_ulogin表
id(pk) uname password
------------------------------
1 zz 123
2 xx 123
t_udetail表
id(pk+fk) realname adress phonenum
-----------------------------------------
1 杂杂 xcccv 123365
2 学习 csdsd 462616
--外键唯一
t_udetail表中的一个userid字段用t_ulogin表的主键,并且该字段unique约束
t_ulogin表
id(pk) uname password
------------------------------
1 zz 123
2 xx 123
t_udetail表
id(pk) realname adress phonenum userid(fk+unique)
-------------------------------------------------------------------
1 杂杂 xcccv 123365 1
2 学习 csdsd 462616 2
--一对多的变形,多的表中外键加了unique约束
数据表的几种的关系
- 一对一:学生和学生证
- 一对多:学生和班级
- 多对多:学生和课程
如何表示数据库表之间的关系
- 使用外键:数据库外键关系表示的其实是一种一对多的关系
- 一对一:外键+唯一
- 多对多:引入中间表,把一个多对多表示为两个一对多
4、表设计的三大范式
所谓范式,即如何建立科学的,规范的的数据库,需要满足一些规范的来优化数据数据存储方式的指导办法。
第一范式(1NF)
- 每一列属性都是不可再分的属性值,确保每一列的原子性
- 合理的根据实际业务数据需求来决定属性,合并相似或相同的列,避免冗余
假如有一个业务需求是:需要了解一批用户的基础信息(包括姓名,年龄,电话,详细地址,以及根据地址明细进行分类),如果数据库表设计如下,则不满足第一范式:
不满足第一范式示例
以上实例中设计了地址
,如果需求根据省
,市
进行分类则无法实现
【解决办法】根据需求适当的将地址拆分为更原子的省市两个属性即可符合第一范式
第二范式(2NF)
- 需要确保数据库表中的每一列都和主键相关,如果是联合主键,则需要和所有主键均相关而不能只与主键和某一部分相关
- 在一个数据库表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中
假设有表如下,学号和课程编号是联合主键,但是,该表中,课程名称和学号没有任何关系,学生姓名和课程编号也没有任何关系
不满足第二范式示例
【解决办法】(1)提取学生表;(2)提取课程表;(3)建立学生课程关系表。
值得注意的是,学生表只存储学生的基本信息属性;课程表只存储课程的相关属性;学生课程关系表,只存储学号(学生表主键)和课程编号(课程表主键)以及一些其他学生课程关系的属性字段,并不存储学生基本信息和课程相关信息,即可符合第二范式
第三范式(3NF)
- 确保数据表一个记录中的数据都和主键直接相关,而不是间接相关,不能存在传递关系
- 属性不依赖于其他非主属性
假设有如下表,学号为主键,它存在 学号 --> 班级编号 --> 班级信息
这么一个主键学号与班级信息的传递关系,不符合第三范式
不符合第三范式示例
【解决办法】(1)提取学生表;(2)提取班级表;
学生肯定在某一个班级中,所以班级编号可以作为学号(主键)的一个直接关联属性,但班级的其他信息应该放在以班级编号为主键的表中,即可符合第三范式。
遵循范式的优缺点
通过以上的了解,可以发现,范式规则有如下特点
- 结构合理,表含义容易理解及区分
- 冗余较小
- 但性能有所降低,多表查询比单表效率低下
五大约束:
数据库中的五大约束包括:
1.主键约束(Primay Key Coustraint) 唯一性,非空性;
2.唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个;
3.默认约束 (Default Counstraint) 该数据的默认值;
4.外键约束 (Foreign Key Counstraint) 需要建立两表间的关系;
5.非空约束(Not Null Counstraint):设置非空约束,该字段不能为空。
五大约束的语法示例:
\1. 添加主键约束
Alter table 表名 add Constraint 主键名 primary key(字段)
\2. 添加唯一约束
Alter table 表名 add Constraint 约束名 unique(字段)
\3. 添加默认约束
Alter table 表名 add Constraint 约束名 default(默认内容) for 字段名
\4. 添加检查约束
Alter table 表名 add Constraint 约束名 check (字段表达)
\5. 添加外键约束
Alter table 表名 add Constraint 约束名 foreign key(字段) references 表名(字段名)
详细介绍:
(1)[外键约束 (Foreign Key Counstraint) ]
1.设置外键的注意事项:
①:只有INNODB的数据库引擎支持外键,修改my.ini文件设置default-storage-engine=INNODB;
②:外键与参照列的数据类型必须相同。(数值型要求长度和无符号都相同,字符串要求类型相同,长度可以不同);
③:设置外键的字段必须要有索引,如果没有索引,设置外键时会自动生成一个索引;
2.设置外键的语法:
[CONSTRAINT 外键名] FOREIGN KEY(外键字段) REFERENCES 参照表(参照字段) [ON DELETE SET NULL ON UPDATE CASCADE] -- 设置操作完整。
3、外键约束的参照操作:
当对参照表的参照字段进行删除或更新时,外键表中的外键如何应对。
参照操作可选值:
RESTRICT: 拒绝对参照字段的删除或修改(默认);
NO ACTION:与RESTRICT相同,但这个指令只在MySql生效;
CASCADE: 删除或更新参照表的参照字段时,外键表的记录同步删除或更新;
SET NULL: 删除删除或更新参照表的参照字段时,外键表的外键设为NULL (此时外键不能设置为NOT NULL)。
(2)[主键约束](Primay Key Coustraint)
1.主键的注意事项:主键默认非空,默认唯一性约束,只有主键可以设置自动增长(主键不一定自增,自增一定是主键)。
2.设置主键的方式:
①:在定义列时设置:id INT UNSIGNED PRIMARY KEY。
②:在列定义完成后设置:PRIMARY KEY(id)。