第一范式 是数据库规范化中所使用的一种正规形式。第一范式是为了要排除 重复组 的出现,所采用的方法是要求数据库的每个字段都只能存放单一值,而且每笔记录都要能利用一个惟一的主键来加以识别。
重复组
重复组通常会出现在会计账上,每一笔记录可能有不定个数的值。举例来说:
交易
顾客 日期 数量
Pete Monday 19.00-28.20
Pete Wednesday -84.00
Sarah Friday 100.00150.00-40.00
‘数量’ 就是所谓的重复组了,而在这种情况下这份数据就不符合第一范式。想要消除重复组的话,只要把每笔记录都转化为单一记录即可:
交易
顾客 日期 数量
Pete Monday 19.00
Pete Monday -28.20
Pete Wednesday -84.00
Sarah Friday 100.00
Sarah Friday 150.00
Sarah Friday -40.00
缺乏唯一识别码
一样是在交易这个例子中,同一天同一个人买了同样的数量,这样的交易做了两次:
交易
顾客 日期 数量
Pete Monday 19.00
Pete Monday 19.00
如上所示,这两笔交易可以说是一模一样,也就是说如果只靠这些数据我们没有办法分辨这两笔记录。我们之所以说它不符合第一范式,是因为上面这样的表示法欠缺一个唯一识别码,可以是一个字段,也可以是一组字段,而且可以保证在这个数据中唯一识别码不会重复出现。要将它正规化到符合第一范式的原则只需要加入一个唯一识别码即可:
交易
交易 ID 顾客 日期 数量
1 Pete Monday 19.00
2 Pete Monday 19.00
第二范式 是数据库规范化中所使用的一种正规形式。它的规则是要求数据表里的所有数据都要和该数据表的主键有完全依赖关系;如果有哪些数据只和主键的一部分有关的话,就得把它们独立出来变成另一个数据表。如果一个数据表的主键只有单一一个字段的话,它就一定符合第二范式。
一个数据表符合第二范式当且仅当
它符合第一范式
所有非主键的字段都一定和主键有关
有一个数据表记录了设备组件的信息,如下所示:
组件来源
组件 ID (主键) 价格 供应商ID (主键) 供应商名称 供应商住址
65 59.99 1 Stylized Parts VA
73 20.00 1 Stylized Parts VA
65 69.99 2 ACME Industries CA
这个数据表的每个值都是单一值,所以它符合第一范式。因为同一个组件有可能由不同的供应商提供,所以得把组件 ID 和供应商 ID 合在一起组成一个主键。
组件(关键词)和价格之间的关系很正确:同一个组件在不同供应商有可能会有不同的报价,所以价格确实和主键完全相关(完全依赖)。
另一方面,供应商的名称和住址就只和供应商 ID 有关(部分依赖),这不符合第二范式的原则。仔细看就会发现 “Stylized Parts” 这个名称和 “VA” 这个住址重复出现了两次;要是它改名了或是被其他公司并购了怎么办?这时候最好把这些数据存到第二个数据表中:
供应商
供应商 ID (主键) 名称 住址
2 ACME Industries CA
1 Stylized Parts VA
这么一来,原本的 “组件来源” 数据表就得要做相对应的改动:
组件来源
组件 ID (主键主键) 价格 供应商 ID(主键、非关键词)
65 59.99 1
73 20.00 1
65 69.99 2
第三范式 是数据库规范化中所使用的一种正规形式,用来检验是否所有非键属性都只和候选键有相关性,也就是说所有非键属性互相之间应该是无关的。
第三范式和第二范式不同的地方在于,在第三范式里,所有的非键属性都必须和每个候选键有直接相关。如果再对第三范式做进一步加强就成了BC范式,它所强调的重点就在于 “数据间的关系是奠基在键上、以整个键为考量、而且除了键之外不考虑其他因素”。
以下面这个定义机械组件的关系为例:
机械组件
组件编号
(主键) 制造商名称 制造商地址
1000 Toyota Park Avenue
1001 Mitsubishi Lincoln Street
1002 Toyota Park Avenue
本例中制造商地址很明显地不该被列在这个关系里面,因为和组件本身比起来,制造商地址应该和制造商比较有关系;正确的做法应该是把独立成为一个新的数据表:
制造商
制造商名称
(主键) 制造商地址
Toyota Park Avenue
Mitsubishi Lincoln Street
然后把原本的数据表改成这样:
机械组件
组件编号
(主键) 制造商名称
1000 Toyota
1001 Mitsubishi
1002 Toyota
先前那个数据表的问题在于每提到一次制造商名称就要多存一次它的地址,而这就不符合第三范式的原则。
下面提供了另一个例子:
订单 (Order)
订单编号 (ORDER NUMBER)
(主键) 客户名称 (CUSTOMER NAME) 单价 (UNIT PRICE) 数量 (QUANTITY) 小计 (TOTAL)
1000 David $35.00 3 $105.00
1001 Jim $25.00 2 $50.00
1002 Bob $25.00 3 $75.00
在本例中,非主键字段完全依赖于主键订单编号,也就是说唯一的订单编号能导出唯一非主键字段值,符合第二范式。第三范式要求非主键字段之间不能有依赖关系,显然本例中小计依赖于非主键字段单价和数量,不符合第三范式。小计不应该放在这个数据表里面,只要把单价乘上数量就可以得到小计了;如果想要符合第三范式的话,就把小计拿掉吧 (不过在做查询的时候,本来用 “SELECT Order.Total FROM Order” 就要改成用 “SELECT UnitPrice * Quantity FROM Order” 了)。
订单 (Order)
订单编号 (ORDER NUMBER)
(主键) 客户名称 (CUSTOMER NAME) 单价 (UNIT PRICE) 数量 (QUANTITY)
1000 David $35.00 3
1001 Jim $25.00 2
1002 Bob $25.00 3