定义
2NF有以下几条要求:
- 建立在1NF之上
- 不含有部分依赖(Partial Dependency)
示例1
要求1好理解,但是在要求2中的部分依赖是什么意思?让我们通过一个示例来理解。以下面我们建议了一个用户订单表。
CREATE TABLE Custom_Order(
ID INT NOT NULL,
Custom_ID INT NOT NULL,
Custom_Name VARCHAR (20) NOT NULL,
Order_ID INT NOT NULL,
Sale_Date DATETIME NOT NULL,
Order_Detail DOUBLE NOT NULL,
PRIMARY KEY (ID)
);
该表满足1NF,但不满足2NF,因为主键和列存在部分依赖关系:
- Custom_Name依赖于Custom_ID。这里的依赖是指即每个用户的编号是唯一的,而名称绑定于这个唯一的ID。即,一个编号只对应一个用户名,而一个用户名可能有多个编号(用户名可以相同)。
- 客户名与其所购买的商品之间没有直接联系。
所以,Custom_Name 是有依赖的。 同时,订单这个主体也应该独立开,即 Sale_Date 和 Detail 都是有依赖的。若要使此表符合2NF,我们需要将表分成三个表。一个用户表(Customs表),定义用户的相关信息;一个订单表(Orders),表示订单详细信息;一个用户订单表(CustomOrders表)记录用户交易的相关信息。三个表如下所示。
-- 用户信息表
CREATE TABLE Customs(
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
PRIMARY KEY (ID)
);
-- 订单表
CREATE TABLE Orders(
ID INT NOT NULL,
Detail DOUBLE NOT NULL,
PRIMARY KEY (ID)
);
-- 用户订单表
CREATE TABLE CUSTMERORDERS(
Custom_ID INT NOT NULL,
Order_ID INT NOT NULL,
Sale_Date DATETIME,
PRIMARY KEY (CUST_ID, ORDER_ID)
);
通过这个示例我们可以看到,所谓的部分依赖指的是某个(或多个)列依赖于别的列,且和和其他的列没有任何直接关系。当表的设计中有部分依赖时,我们需要将一张表拆分成多张表,这些表包括基本信息表(如Customs表和Orders表)和关系表(如CustomOrders表),从而消除数据的部分依赖。这和设计模式中常说的耦合是一个原则,要尽可能实现低耦合高内聚(low in coupling and high in cohesion)。
示例2
再举行一例,我们从数据冗余角度来看2NF。
编号 | 姓名 | 性别 | 领导姓名 | 领导性别 |
---|---|---|---|---|
1001 | 张三 | 男 | ||
1002 | 李小四 | 女 | 张三 | 男 |
如上表所示,我们在个人信息表中包括了其领导的相关信息。领导的信息都使用了实际的值,而不是引用。这样就违反了2NF,在实际应用中就会带来麻烦。比如,李小四的领导换人了,那么需要同时更新“领导姓名”和“领导性别”两列,如果有多个属性,那么就进行相应的更新。在实际应用中,如果很容易出错,导致数据不同步。
所以,根据2NF的原则,我们修改表的结构如下所示。
编号 | 姓名 | 性别 | 领导编号 |
---|---|---|---|
1001 | 张三 | 男 | 0 |
1002 | 李小四 | 女 | 1001 |
通过对编号的引用,避免了数据不同步的问题,这样无论某人的信息如何修改,编号都不需要改变,在实际显示的时候只需要根据SQL进行联接即可。
总结
2NF要求数据表中对列的引用不能有部分依赖,可以理解为在对不同表的数据引用时,要引用其编号而不是实际的数据。这样带来的设计好处是,数据冗余小(只有编号)且易于修改(修改了被引用表的数据对原表没有影响)。