数据库三大范式

总共有八大范式:1NF,2NF,3NF,BCNF,4NF,5NF,DKNF,6NF。

参考https://blog.csdn.net/qingking520/article/details/52937728和https://www.zhihu.com/question/24696366



1NF的定义为:符合1NF的关系中的每个属性都不可再分。

◆ 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。 

考虑这样一个表:【联系人】(姓名,性别,电话) 

如果在实际场景中,一个联系人有家庭电话和公司电话,那么这种表结构设计就没有达到 1NF。要符合 1NF 我们只需把列(电话)

拆分为==》即:【联系人】(姓名,性别,家庭电话,公司电话)。




1NF 很好辨别,但是 2NF 和 3NF 就容易搞混淆。

这里最好先理解一下概念

码:关系中的某个属性或者某几个属性的组合,用于区分每个元组(可以把“元组”理解为一张表中的每条记录,也就是每一行)

设 K 为某表中的一个属性或属性组,若除 K 之外的所有属性都完全函数依赖于 K(这个“完全”不要漏了),那么我们称 K 为 候选码,简称为 。在实际中我们通常可以理解为: 假如当 K 确定的情况下,该表除 K 之外的所有属性的值也就随之确定,那么 K 就是码。一张表中可以有超过一个码。(实际应用中为了方便,通常选择其中的一个码作为 主码
例子:(学号、课名) 这个属性组就是码。
非主属性
包含在任何一个码中的属性成为主属性。其他的都为非主属性 除了学号课程都是非主属性

函数依赖
我们可以这么理解(但并不是特别严格的定义):若在一张表中,在属性(或属性组)X的值确定的情况下,必定能确定属性Y的值,那么就可以说Y函数依赖于X,写作 X → Y。也就是说,在数据表中,不存在任意两条记录,它们在X属性(或属性组)上的值相同,而在Y属性上的值不同。这也就是“函数依赖”名字的由来,类似于函数关系 y = f(x),在x的值确定的情况下,y的值一定是确定的。

例如:对于表3中的数据,找不到任何一条记录,它们的学号相同而对应的姓名不同。所以我们可以说姓名函数依赖于学号,写作 学号 → 姓名。但是反过来,因为可能出现同名的学生,所以有可能不同的两条学生记录,它们在姓名上的值相同,但对应的学号不同,所以我们不能说学号函数依赖于姓名。

完全函数依赖

在一张表中,若 X → Y,且对于 X 的任何一个真子集(假如属性组 X 包含超过一个属性的话),X ' → Y 不成立,那么我们称 Y 对于 X 完全函数依赖,记作 X F→ Y。(那个F应该写在箭头的正上方,没办法打出来……,正确的写法如图1




  • 学号 F→ 姓名
  • 解释:姓名完全依赖于学号,这里只有一个属性,所以是完全依赖
  • (学号,课名) F→ 分数 (注:因为同一个的学号对应的分数不确定,同一个课名对应的分数也不确定)
解释:分数不能靠单一一个属性(学号或者课名)确定,所以X的 真子集X ' → Y 不成立,所以 分数完全依赖于学号,课名


部分函数依赖

假如 Y 函数依赖于 X,但同时 Y 并不完全函数依赖于 X,那么我们就称 Y 部分函数依赖于 X,记作 X P→ Y,如图2


  • (学号,课名) P→ 姓名

解释:姓名可以通过学号确定,非完全函数依赖。


◆ 第二范式(2NF):首先是 1NF成立,另外包含两部分内容,一是表必须有一个主码;二是没有包含在主码中的列必须完全依赖于主码,而不能只依赖于主码的一部分。 
考虑一个订单明细表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。
因为我们知道在一个订单中可以订购多种产品,所以单单一个 OrderID 是不足以成为主码的,主码应该是(OrderID,ProductID)。显而易见 Discount(折扣),Quantity(数量)完全依赖(取决)于主码(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID。所以 OrderDetail 表不符合 2NF。不符合 2NF 的设计容易产生冗余数据。

可以把【OrderDetail】表拆分为【OrderDetail】(OrderID,ProductID,Discount,Quantity)和【Product】(ProductID,UnitPrice,ProductName)来消除原订单表中UnitPrice,ProductName多次重复的情况。

查看是否符合第二范式:

第一步:找出数据表中所有的
第二步:根据第一步所得到的码,找出所有的主属性
第三步:数据表中,除去所有的主属性,剩下的就都是非主属性了。
第四步:查看是否存在非主属性对码的部分函数依赖

这里订单明细表 主码应该是(OrderID,ProductID)

主属性:OrderID,ProductID

非主属性:UnitPrice,Discount,Quantity,ProductName

Discount(折扣),Quantity(数量)完全依赖(取决)于主码(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID。存在非主属性( UnitPrice,ProductName对码(OrderID,ProductID)的部分函数依赖(于ProductID。不是完全的函数依赖。


看起来很麻烦是吧,但是这里有一个诀窍,就是假如A是码,那么所有包含了A的属性组,如(A,B)、(A,C)、(A,B,C)等等,都不是码了(因为作为码的要求里有一个“ 完全 函数依赖”)。


◆ 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
考虑一个订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID)。
其中 OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 等非主键列都完全依赖于主键(OrderID),所以符合 2NF。不过问题是 CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。


主码:OrderID

主属性:OrderID

非主属性:OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity

这里OrderIDOrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 符合第二范式,都是完全依赖

但是CustomerIDCustomerName,CustomerIDCustomerAddrCustomerIDCustomerCity 存在传递。所有不符合第三范式。


通过拆分【Order】为【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到 3NF。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值