SQL 范式
本文将详细说明一个重要的SQL概念,即规范式。
规范化是一种数据库设计技术,可以消除插入、更新和删除异常,减少数据冗余和重复。规范化过程将较大的表拆分为较小的表,然后通过关系连接这些较小的表。SQL中的规范化目标是摆脱多余的(重复的)数据,并确保数据保持正确。
一组称为规范形式的准则成为规范化过程的基础。使用这些规则可以减少或消除当数据保存在单个表中时可能发生的异常、不一致和数据重复。
创造关系模型的发明者Edgar Codd从第一范式开始引入了数据规范化的概念,并继续通过第二范式和第三范式进行改进。后来,他与Raymond F. Boyce合作建立了Boyce-Codd规范形式理论。
不同类型的规范形式
存在不同的规范化阶段,每个阶段都有自己的需求和标准,下面将提到和解释它们。
- 1NF(第一范式)
- 2NF(第二范式)
- 3NF(第三范式)
- 4NF(第四范式)
- 5NF(第五范式)
1NF
如果表遵循以下两个准则/规则,则关系数据被认为是在第一范式中。
- 每个表格单元格中应该只有一个值(原子性)。
- 每条记录应该是不同和唯一的。
请考虑下面的示例以理解第一范式。
例子: 让我们考虑下面的学生表以理解第一范式的概念。
Roll_no | Name | Courses_enrolled |
---|---|---|
11 | Ram | English, Biology |
12 | Samuel | Maths, Physics |
13 | Rehman | Chemistry |
正如我们在前两条记录中观察到的那样,Courses_enrolled列在一个特定的表格单元格中有多个值。所以,这违反了第一范式的规则。为了纠正这个问题,我们需要拆分这个表,并且两部分都应该包含一个共同的列/属性。这个列就是超键。为了理解简化版本的超键是什么,超键是用于唯一标识所有记录的属性。
所以,表格被分成如下几部分:
学生表:
Roll_no | Name |
---|---|
11 | Ram |
12 | Samuel |
13 | Rehman |
课程表:
Roll_no | Course |
---|---|
11 | English |
11 | Biology |
12 | Maths |
12 | Physics |
13 | Chemistry |
所有表格的记录是原子的(每个表格单元格包含单个值),并且所有记录都是唯一的。因此,上述关系数据被称为1NF。
2NF
如果表格满足以下两个条件/规则,则关系数据被认为是第二范式。
- 数据应该是1NF。
- 表格中的每个非主键列应该依赖于完整的主键,而不只是其中的一部分。
例如: 考虑以下名为“sales”的表格的数据如下:
order_id | Customer_id | Customer name | Product_id | Quantity | Product_name |
---|---|---|---|---|---|
101 | 121 | James | 32 | 3 | Laptop |
102 | 122 | Rodes | 33 | 1 | Tablet |
103 | 123 | Williams | 34 | 2 | Shirts |
104 | 124 | Smith | 35 | 1 | Watches |
观察表格,我们可以发现主键不是单个属性,而是由两个属性组成,它们是customer_id和order_id。在这里,Customer_name属性只取决于customer_id列,而不取决于order_id列。这与第二范式规则相矛盾。
因此,为了纠正这个问题,销售表需要被分成两个单独的表,一个是订单表,另一个是顾客表。
订单表:
order_id | Customer_id | Product_id | Quantity |
---|---|---|---|
101 | 121 | 32 | 3 |
102 | 122 | 33 | 1 |
103 | 123 | 34 | 2 |
104 | 124 | 35 | 1 |
客户表:
Customer_id | Customer name |
---|---|
121 | James |
122 | Rodes |
123 | Williams |
124 | Smith |
3NF
如果表格满足下面的两个标准/规则,则关系数据被认为是满足三范式的。
- 数据应该满足2NF。
- 所有非主键列只能依赖于主键,不能依赖于任何其他非主键列。
例如: 考虑下面的例子来清楚地理解第三范式的概念。
员工编号 | 姓名 | 部门 | 部门编号 | 经理编号 | 经理姓名 | 工资 |
---|---|---|---|---|---|---|
501 | James | 市场营销 | 121 | 101 | Jane Hoper | 20000 |
502 | Johnson | 测试 | 122 | 102 | William Smith | 50000 |
503 | David | 研发 | 123 | 103 | Michal Doe | 75000 |
这里的主键是employee_id属性。部门,经理姓名和薪水列不仅依赖于员工ID,还依赖于经理ID属性。这与第三范式规则相矛盾。
为了纠正它并将其结构化为第三范式,我们需要将整个表分成3个部分,其中一部分是员工,第二部分是部门,最后一部分是经理。
员工表:
Employee_id | Name | Department_id | Manager_id | Salary |
---|---|---|---|---|
501 | James | 121 | 101 | 20000 |
502 | Johnson | 122 | 102 | 50000 |
503 | David | 123 | 103 | 75000 |
部门表
部门编号 | 部门名称 |
---|---|
121 | 市场营销 |
122 | 测试 |
123 | 研发 |
管理员表:
Manager_id | Manager_name |
---|---|
101 | Jane Hoper |
102 | William Smith |
103 | Michal Doe |
现在,Manager_name列仅取决于Manager_id列,而Department和Salary列仅取决于Department_id和Employee_id列。这符合第三范式的标准。
4NF
如果表格符合以下两个条件/规则,则关系数据称为第四范式:
- 数据已经符合第三范式
- 关系数据不应具有任何非平凡的多值依赖关系。
首先,我们需要了解什么是多值依赖关系。
当属性或属性组合可以对另一个属性或属性组合的单个值具有多个值时,此情况被称为多值依赖关系(MVD)。
例如: 考虑下面的示例来清楚地理解第四范式的概念。考虑下面的“orders”表,其中包含以下数据
order_id | Customer_id | Customer name | Product_id | Product_name | Product_description |
---|---|---|---|---|---|
101 | 121 | James | 32 | Laptop | Gaming Laptop |
101 | 121 | James | 33 | Book | Fiction Story |
103 | 122 | Rodes | 33 | Book | Fiction Story |
104 | 124 | Smith | 35 | Watches | Smart watch |
104 | 124 | Smith | 36 | Shirt | Formal Shirt |
在这个表中,我们可以清楚地观察到存在多值依赖关系,因为每个订单ID和产品ID的组合都存在多个产品名称和产品描述的值。例如,订单ID 101和产品ID 32具有产品名称为“笔记本电脑”和产品描述为“游戏笔记本电脑”,而订单ID 101和产品ID 33具有产品名称为“书”和产品描述为“小说故事”。 因此,为了消除这种多值依赖关系并将上述数据结构化为第四范式,我们需要将整个表分成两个部分:一个用于订单,另一个用于产品。因此,结果为:
订单表:
order_id | Customer_id | Customer name |
---|---|---|
101 | 121 | James |
103 | 122 | Rodes |
104 | 124 | Smith |
产品表:
order_id | Product_id | Product_name | Product_description |
---|---|---|---|
101 | 32 | Laptop | Gaming Laptop |
101 | 33 | Book | Fiction Story |
103 | 33 | Book | Fiction story |
104 | 35 | Watches | Smart Watch |
104 | 36 | Shirt | Formal Shirt |
现在,结果表在没有多值依赖的情况下看起来是第四范式。
5NF
当一个表的所有非平凡依赖都基于主键时,该表被认为是在第五范式下被规范化了。因此,数据库中没有冗余,并且由于重复的更新而带来的任何潜在的数据异常也被消除了。
例子:
考虑以下表格以说明第五范式:
Book_id | Title | Author_ID | Author Name | Author email |
---|---|---|---|---|
11 | Python for beginners | 101 | K. Kishore | stash |
11 | Python for beginners | 102 | L. Ravi | stash |
12 | Software testing | 103 | P. Gopi | stash |
12 | Software testing | 104 | R. Joseph | stash |
关系型数据是冗余的,即同一本书的名称分配给了两个作者。由于这种冗余,更新一个作者的电子邮件可能需要更新表中该作者的所有其他实例。
为了应用第五范式,我们必须在表中找到多值依赖关系。在此实例中,“图书编号”和“作者编号”属性之间存在多值依赖关系,因为一本书和一个作者都可以有多个作者。
基于多值依赖关系,我们可以将“图书”表分为两个表,“图书”和“作者”。新表中将存在以下属性:
图书表:
Book_id | Title |
---|---|
11 | Python for beginners |
12 | Software testing |
作者表:
Author_ID | Author Name | Author email |
---|---|---|
101 | K. Kishore | stash |
102 | L. Ravi | stash |
103 | P. Gopi | stash |
104 | R. Joseph | stash |
现在通过将表分解成两个新表来消除原始表中的冗余。此分解已满足第五范式的要求。因此,上述关系数据已经结构化为第五范式。