范式—设计关系型数据库的准则
关系型数据库是目前流行和使用广泛的数据库,关系型数据库的设计标准就是数据库的范式,范式分别有第一范式、第二范式、第三范式。
1. 第一范式—关系型数据库设计的第一步
目前,只要是使用关系型数据库来设计数据库,都能够满足数据库设计的第一范式。
第一范式(1NF)就是数据库表中的字段都是单一属性的,不可再分。这个单一属性可以是数据库中任何一种基本数据类型,如整型、字符型、日期型等。只要是关系型数据库都会满足第一范式。
例如,一个产品信息表 (product),描述产品信息的字段有产品编号、产品名称、产品数量、产品价格、产品描述,如表所示,那么这个产品信息表就满足第一范式的要求:每一个字段都是不可再分的单一属性。
字段名 | 数据类型 |
---|---|
产品编号 | 整数 |
产品名称 | 字符型 |
产品数量 | 整数 |
产品价格 | 实型 |
产品描述 | 字符型 |
2. 第二范式—关系型数据库设计的第二步
第二范式是在第一范式的基础上进一步对关系型数据库进行规范,官方给出第二范式的定义是要求在数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖。意思就是说在第二范式中组合主键(AB)里面的 A 或者 B 与其他字段不能存在组合重复。
为解决这个问题,通常的做法是不用组合主键,添加一个编号列,作为单一主键即可满足第二范式。
如果不想添加编号列,就满足组合主键(AB)里面的 A 或者 B 与其他字段不能存在组合重复。
例如,设计一个购物信息表,字段包括客户编号、产品名称、产品数量、产品类型、产品价格、客户类型。如果用客户编号和产品名称作为组合主键,那么在组合主键中产品名称和产品类型存在一定关系,是由产品名称决定产品的类型,所以不符合第二范式的要求,如果不按照第二范式的要求设计表,就会出现以下 4 个问题:
-
数据冗余
同一个产品由 n 个顾客购买,
产品类型
就重复 n-1 次;同一个顾客购买了多件产品,那么就会多次记录顾客的个人信息。 -
更新异常
若调整了某个产品的类型,数据表中所有行的
产品类型
值都要更新,否则会出现同一个产品不同类型的情况。 -
插入异常
假设新进了一个产品,暂时还没有人购买。这样,由于没有人购买,产品的名称和类型也无法记录到数据库中。
-
删除异常
假设一批顾客把已经购买完的商品退货,这些产品信息就从数据表中删除了。但是,与此同时,产品名称和产品类型等信息也被删除了。这样就导致了删除异常。
为了消除数据冗余、更新异常、插入异常和删除异常,可以把现有的一个表拆分成 3 张表:
第 1 张表是产品类型表,表中有产品类型、产品名称。
第 2 张表是客户信息表,表中有客户编号、客户类型。
第 3 张表是产品信息表,表中有产品名称、产品类型、产品价格、产品数量。
3. 第三范式—关系型数据库设计的第三步
第三范式是在第二范式的基础上对数据库设计进行规范,第三范式的要求是数据表中不存在非关键字段对任一候选关键字段的传递函数依赖。
所谓传递函数依赖,指的是如果存在 A 决定 B、B 决定 C 的决定关系,则 C 传递函数依赖于 A。因此,满足第三范式的数据库表应该不存在依赖关系,假定员工信息表为 employee(员工编号,姓名,年龄,所在部门,部门电话),使用员工编号作为员工信息的主键,那么就存在决定关系:员工编号就决定了姓名、年龄、所在部门、部门电话这些字段。
从上面的关系可以看出,在表中有一个主键,数据表的设计符合第二范式的要求。但是它不符合第三范式的要求,因为存在决定关系:员工编号就决定了所在部门,所在部门又决定了所在部门的电话,那么就存在了传递函数依赖关系,即员工编号决定部门电话,那么也会出现不满足第二范式时的数据冗余和更新、插入、删除异常的情况。为了满足第三范式的要求,必须把员工信息表拆分成如下两个数据表:
-
员工表:员工编号、姓名、年龄、所在部门;
-
部门表:部门名称、部门电话。
除了上面的三种范式以外,还有一种范式经常使用,即鲍依斯 - 科得范式(BCNF)。
它建立在第三范式的基础上,如果数据库表中不存在任何字段对任一候选关键字段的传递函数依赖,那么就符合 BCNF 范式。