表规范化过程

数据库的规范化

在介绍多表查询之前,我们先讨论一下产生多表查询的主要原因。图7-1是一张简化了的公司订单。其公司的名字为:天上人间快餐大中华总店。

如何基于这张订单来设计一个关系数据库的表呢?一种最简单的办法是把该订单的所有数据存放在一个表中,并用订单号和商品号做主键(Primary Key)。

图7-2并不是一个关系数据库的表。因为所有的关系数据库表中的每一行必须有一主键并且要满足实体完整性(Entity Integrity)。图7-2中的阴影部分叫重复组(Repeating Groups)或重复属性。关系数据库表中是不能含有重复组(Repeating Groups)的。

那么什么样的表是关系数据库的表呢?在回答这一问题之前,我们先介绍两个在关系数据库中非常重要的概念:主键(Primary Key)和实体完整性(Entity Integrity)。

主键(Primary Key):它是关系数据库表中的某一列或某几列的组合;它能够惟一地标识关系数据库表中的任一行。

实体完整性(Entity Integrity):主键(Primary Key)不能包含空值(NULL),并且主键(Primary Key)必须能够惟一地标识任一行。

表的设计者负责定义主键(Primary Key),关系数据库管理系统(如Oracle)负责维护实体完整性(Entity Integrity)。

根据实体完整性(Entity Integrity)的定义,图7-2显然不是一个关系数据库的表,因为在这个表中有些行的主键部分是空的。

我们可以对图7-2做一些修改,使之变成关系数据库的表(Order)。如图7-3所示。

图7-3已经是一个关系数据库表。您现在能看出该表在实际应用中的问题吗?假设商品号为2351的龙卷风牌一次性筷子是天上人间快餐大中华总店经常订的商品,而天上人间快餐大中华总店已发展成一个跨地域的连锁店,该公司每年可能要订购2351号商品上百次。也就是说2351号商品的信息要在Order表中重复上百次。这样出现输入错误的可能性大为增加,从而产生相同的商品在同一表中不同的行中记录的信息为不同的,也就是所谓的数据不一致。

数据的不一致性是由于相同数据的重复存放,即冗余造成的。数据的冗余不但会造成数据不一致,还会使系统的维护更加困难,也会对系统的效率产生冲击。

如何减少数据的冗余呢?实际上图7-3所示的Order表是一个第一范式(1NF)的表。任何关系数据库的表都满足第一范式(1NF)。

第一范式(1NF):

(1)所有的键属性(列)都已定义;

(2)没有任何重复组(Repeating Groups),换句话说,每行和每列的交汇处可以而且只能包含一个值,而不能包含一组值;

(3)所有的属性(列)都依赖于主键。

消除部分依赖

仔细分析图7-3所示的Order表您就会发现,我们只要知道了某一商品的商品号就能知道该商品的全部信息,即商品其他部分的信息只依赖于商品号。图7-4为表示此关系的依赖关系图。

依赖关系图是一个帮助我们找到依赖关系的非常有效的工具。由图7-4可以很清楚地看出:商品所有其他部分的信息都依赖于商品号。因为商品号只是主键的一部分,所以这种依赖关系也叫部分依赖。

部分依赖(Partial Dependency):只依赖于部分主键的依赖关系。

我们可以把存在着部分依赖关系的列拿出来重新生成一个新表叫Product,而把商品号作为新表Product的主键,同时把商品号也保留在新的Order表中作为外键(稍后我们将介绍什么是外键)。

现在我们把一个表(Order)拆分成了两个表(Order和Product),如图7-5和图7-6 之间通过商品号来连接。

现在一个商品的信息只需在Product表中存放一次,而Product表中只有商品号在Order 表中可重复存放多次。因此产生的数据的冗余已经大大地减少。

外键(Foreign Key)和引用完整性(Referential Integrity)

那么关系数据库管理系统又是如何从多个表中找到用户所需的信息的呢?使关系数据库工作的机制是控制冗余。

控制冗余:数据库中的表通过共享相同的键属性(列)把它们链在了一起。

例如 Order表和 Product 表就是靠共享商品号链在一起的。商品号在Product 表中是主键,而它在Order表中为外键。

外键(Foreign Key):它是关系数据库表中的某一列或某几列的组合;它的值或者与另一个表中(有时也可能是同一个表中)的某一列(一般为主键(Primary Key))相匹配,或者为空值(NULL)。

引用完整性(Referential Integrity):

(1)外键必须或者为空值(NULL)或者有相匹配的项。

(2)外键可以没有相对应的键属性(列)但不可以有无效的项。

表的设计者负责定义外键(Foreign Key)。关系数据库管理系统(如 Oracle)负责维护引用完整(Referential Integrity)。

第二范式(2NF)

消除重复组(Repeating Groups)和部分依赖的表为第二范式(2NF)的表,因此图7-5 (Order)所示的表已经是第二范式(2NF)的表了。

第二范式(2NF):

(1)该表为第一范式(1NF)的表;(2)该表不包含部分依赖。

如果一个表是第一范式(1NF)的表,并且它的主键由一列(单一属性)组成,那么该表自动地成为第二范式(2NF)的表。我们继续分析图7-5(Order)。

第三范式(3NF)

假设供应商——神州商霸批发有限公司是一个非常好的的供应商,天上人间快餐大中华总店每年要向该公司订购上百次商品。也就是说234510号供应商的信息要在Order表中重复上百次。

现在进一步假设:虽然该供应商在起家时,只不过是在地下防空洞中经营的一个夫妻店,但经过夫妻俩艰苦奋斗和有效经营,生意越来越红火。现在已在本市的商业中心区租下了几层楼,电话也改了,且又增加了8条线,而且又雇了个经理和一大帮推销员。二人已不再参与公司的日常管理了。

虽然这些变化与天上人间快餐大中华总店毫不相干,但由于它的数据库的设计有缺陷,所以这些变化都可能影响到Order表,即可能要修改这个表;而且一个变化可能引起几百行数据的修改。

如何来解决这一问题呢?我们还是先用依赖关系图来分析各个列之间的依赖关系,如图7.6所示。

从图 7.6 可以看出:我们只要知道了某一供应商的供应商号就能知道该供应商的全部信息。即供应商的其他部分的信息只依赖于供应商号。但供应商号不是主键,因此它不属于部分依赖。那么它属于哪种依赖呢?

传递依赖(Transitive Dependency):一个或多个属性(列)依赖于非主键的属性(列)。我们再把存在着传递依赖关系的列拿出来重新生成一个新表叫Supplier,而把供应商号作为新表 Supplier 的主键,同时把供应商号保留在新的 Order 表中作为外键。这样就把最初的一个表分拆成了图7-7、图7-8、图7-9的3个表。

图7-7 Order、图7-8 Supplier和图7-9 Product中的每一个表都有主键并且不包含重复组(Repeating Group),同时也不包含部分依赖和传递依赖。这就是我们所说的第三范式(3NF)。

第三范式(3NF):

(1)该表为第二范式(2NF)的表;(2)该表不包含传递依赖。

对于绝大多数商业数据库设计来说,“第三范式(3NF)”就是规范化过程的终点。

规范化过程小结

规范化:规范化是一个过程,该过程决定把哪些属性(列)放在哪些实体(表)中。规范化可以帮助我们设计好的表结构,因为规范化减少了数据的冗余,这使得系统更容易维护而且系统效率也会更高。

所谓的关系型数据库的逻辑设计就是数据库的表结构设计。在关系型数据库中,只有表中存有数据。

规范化只减少了数据的冗余而并没有完全消除冗余。因为为了使相关的表连接起来,在规范化过程中不得不引入控制冗余(外键)。不过这种控制冗余与第一范式(1NF)和第二范式(2NF)表的数据冗余相比已经少得微不足道了。注意:

本书所介绍的数据库的规范化只是一个简介。其目的是为了帮助读者理解以后章节的一些内容,例如多表连接、DML操作等。

你可能感兴趣的:(sql,数据库)