总共有八大范式: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 就容易搞混淆。
这里最好先理解一下概念
码:关系中的某个属性或者某几个属性的组合,用于区分每个元组(可以把“元组”理解为一张表中的每条记录,也就是每一行)。
包含在任何一个码中的属性成为主属性。其他的都为非主属性 除了学号课程都是非主属性
函数依赖
我们可以这么理解(但并不是特别严格的定义):若在一张表中,在属性(或属性组)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→ 分数 (注:因为同一个的学号对应的分数不确定,同一个课名对应的分数也不确定)
部分函数依赖
假如 Y 函数依赖于 X,但同时 Y 并不完全函数依赖于 X,那么我们就称 Y 部分函数依赖于 X,记作 X P→ Y,如图2。
![](https://i-blog.csdnimg.cn/blog_migrate/ec04fcf8a5d4d57da1e606f9f4a20033.png)
- (学号,课名) 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)。不是完全的函数依赖。
考虑一个订单表【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
这里Order→IDOrderDate,→CustomerID,→CustomerName,→CustomerAddr,→CustomerCity 符合第二范式,都是完全依赖
但是CustomerID→CustomerName,CustomerID→CustomerAddr,CustomerID→CustomerCity 存在传递。所有不符合第三范式。
通过拆分【Order】为【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到 3NF。