数据库设计三大范式

一条SQL背后的故事(四)

数据库三大范式

第一范式(1NF)

第一范式强调每一列都是不可分割的原子数据项。
通俗来讲就是表中的某一个字段,不能再拆分成两个或者多个字段。比如 student 表中 班级/班主任 定义为一个字段,这就违背了第一范式。
第二范式(2NF)
数据表里的非主属性都要和这个数据表的候选键有完全依赖关系
这里就需要先说一下数据表中常用的几种键和属性:

  • 超键 SUPER KEY:能唯一标识元组的属性集叫做超键。比如用户表中(身份证号)、(身份证号、性别)、(身份证号、姓名)
  • 候选键 CANDIDATE KEY:如果超键不包括多余的属性,那么这个超键就是候选键。比如用户表里的身份证号、学生表里的学号、银行卡表里的银行卡号等
  • 主键 PRIMARY KEY:用户可以从候选键中选择一个作为主键。
  • 外键 FOREIGN KEY:如果数据表R1 中的某属性集不是 R1 的主键,而是另一个数据表 R2 的主键,那么这个属性集就是数据表 R1的外键。比如学生表中的课程编号 或者老师编号都是外键。
  • 主属性:包含在任一候选键中的属性称为主属性。
  • 非主属性:与主属性相对,指的是不包含在任何一个候选键中的属性。

比如说我们设计一张球员比赛表 player_game,里面包含球员编号、姓名、年龄、比赛编号、比赛时间和比赛场地等属性。
这里候选键和主键都为(球员编号,比赛编号),
我们可以通过候选键来决定如下的关系:
(球员编号, 比赛编号) → (姓名, 年龄, 比赛时间, 比赛场地,得分)
上面这个关系说明球员编号和比赛编号的组合决定了球员的姓名、年龄、比赛时间、比赛地点和该比赛的得分数据。
但是这个数据表不满足第二范式,因为数据表中的字段之间还存在着如下的对应关系:
(球员编号) → (姓名,年龄)
(比赛编号) → (比赛时间, 比赛场地)
不满足第二范式会出现什么问题呢?
1. 数据冗余:如果一个球员可以参加 m 场比赛,那么球员的姓名和年龄就重复了 m-1 次。一个比赛也可能会有 n 个球员参加,比赛的时间和地点就重复了 n-1 次。
2. 插入异常:如果我们想要添加一场新的比赛,但是这时还没有确定参加的球员都有谁,那么就没法插入。
3. 删除异常:如果我要删除某个球员编号,如果没有单独保存比赛表的话,就会同时把比赛信息删除掉。
4. 更新异常:如果我们调整了某个比赛的时间,那么数据表中所有这个比赛的时间都需要进行调整,否则就会出现一场比赛时间不同的情况。
第三范式(3NF)
表中的非主键列必须和主键直接相关而不能间接相关;也就是说:非主键列之间不能相关依赖。
学生表中,学生属于那个班级,班级就可以确定这个班的班主任老师。所以班主任名称就跟学生的学生号存在相关依赖的关系。

学生表:姓名/年龄        
eg:张三/11,李四/12,王五/11
姓名,年龄分开就符合第一范式
加个学号  就符合第二范式
加个foreign key 就符合第三范式
第三范式降为第二范式 通过冗余字断提效率性能,就是反范式设计。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java~ Jeffery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值