数据库设计原则-范式(1)
下面是八个范式的英文全称:
1NF : First normal form
2NF : Second normal form
3NF : Third normal form
BCNF : Boyce-Codd normal form
4NF : Fourth normal form
5NF : Fifth normal form
DKNF : Domain/key normal form
6NF : Sixth normal form
第一范式(1NF)
在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。
第一范式具体分为下面5个条件:
1.数据表内的的每行没有前后之分。
2.数据表内的每列没有左右之分。
3.没有内容相同的重复行。
4.每个行和列交叉的地方只有一个适用的值,不会出现多个值。
5.每个列的作用都是固定的。
例子:一个电话本的数据表设计
| Uid | UserName | TelNumber |
| 1 | andery | 0571-88888888 |
| 2 | jack | 0571-77777777 |
| 3 | sam | 0571-66666666 |
假设jack拥有2个电话号码,我们这样写:
| Uid | UserName | TelNumber |
| 1 | andery | 0571-88888888 |
| 2 | jack | 0571-77777777 0571-555555555 |
| 3 | sam | 0571-66666666 |
这样写似乎就违反了上面第4条,jack这列的电话号码包含了多个值。同时影响到的还有字段类型和长度的定义。
然后考虑改进方法:给数据表增加一列来解决
| Uid | UserName | TelNumber_1 | TelNumber_2 |
| 1 | andery | 0571-88888888 | |
| 2 | jack | 0571-77777777 | 0571-88888888 |
| 3 | sam | 0571-66666666 |
这样又有问题:
1.andery和sam的TelNumber_2是空的了,很显然不合理。 2.如果用户还有3个,4个或者更多的电话号码怎么办?一直增加列很显然不可取。 3.存放电话号码的属性完全一样,违反了上面的第5条。 4.我们需要查询一个用户电话号码的时候会带来麻烦,这么多列我们到底需要哪一列?并且还有可能为空。
再回过头来考虑把电话号码还是放到一个字段中来,改变字段的数据类型和长度的限制,使他足够长能容纳多个电话号码组成的字符串:
| Uid | UserName | TelNumber |
| 1 | andery | 0571-88888888 |
| 2 | jack | 0571-77777777,0571-555555555 |
| 3 | sam | 0571-66666666 |
我见过不少这样设计的,如果数据表设计和产品设计还有程序都是你一个人干的,或者项目要求不高,电话号码可变性不是很大,还是可行的。老外评价这个是最糟糕的设计!
我的一点看法:
1.字段作用不明确,这个字段到底是电话号码?2个电话组成的字符串?3个电话组成的字符串... 2.电话号码特别多怎么控制这个字段允许的长度? 3.查询的时候我不能预期他是单个电话号码还是多个电话号码。 4.用户需要修改号码的时候,这个就头疼了,不需要多解释了。
下面给出一个符合第一范式的设计:
用户表:
| Uid | UserName |
| 1 | andery |
| 2 | jack |
| 3 | sam |
电话号码表:
| Uid | TelNumber |
| 1 | 0571-88888888 |
| 2 | 0571-77777777 |
| 2 | 0571-555555555 |
| 3 | 0571-66666666 |
把电话号码单独出来一个数据表,这样重复的列(电话号码列)可以合并到一列中,通过用户的ID来和电话表进行连接。
POSTED ON 2010年06月17日,