一、第一范式 1NF
数据表中的所有字段都是不可分割的原子项。
mysql> create table student2( -> id int, -> name varchar(20), -> address varchar(30) -> );
向表中插入数据:
mysql> INSERT INTO student2 VALUES(1,'Rose','SiChuanChengDuROAD311'); mysql> INSERT INTO student2 VALUES(2,'Mary','SiChuanChengDuROAD321'); mysql> INSERT INTO student2 VALUES(3,'Bob','SiChuanChengDuROAD8974'); mysql> select * from student2; +------+------+------------------------+ | id | name | address | +------+------+------------------------+ | 1 | Rose | SiChuanChengDuROAD311 | | 2 | Mary | SiChuanChengDuROAD321 | | 3 | Bob | SiChuanChengDuROAD8974 | +------+------+------------------------+
字段值还可以继续拆分的,就不满足第一范式。比如address就还可以在拆分出country,city等更细的划分。
范式设计的越详细,对于某些实际操作可能更好,但是不一定都好,要依据具体应用场景而定。
二、第二范式 2NF
必须是满足第一范式的前提下,第二范式要求,除主键外的每一列都必须完全依赖于主键。
如果要出现不完全依赖,只可能发生在联合主键的情况下。
创建一张订单表:
mysql> create table my_order( -> product_id int, -> customer_id int, -> product_name varchar(20), -> customer_name varchar(20), -> primary key(product_id,customer_id) -> );
product_id与customer_id共同组成主键。
有什么问题?
customer_name只与customer_id有关,与product_name及product_id无关。同理,product_name只与product_id有关,与customer无关。
这就叫做:除主键之外的列(eg.product_name)不完全依赖于主键(eg.customer_id)。
也就是:这些主键之外的其他列(eg.product_name),只依赖于主键的部分字段(eg.product_id)。
即:不满足第二范式。
如何做才能让它满足第二范式?拆表!
mysql> create table my_order( -> order_id int primary key, -> customer_id int, -> product_id int -> ); mysql> create table product( -> id int primary key, -> name varchar(20) -> ); mysql> create table customer( -> id int primary key, -> name varchar(20) -> );
此上三个表中,除主键之外的列是完全依赖于主键的。
为什么要分表?因为分表之后让其满足第二范式设计。
三、第三范式 3NF
必须在满足第二范式的前提下,除开主键列的其他列之间不能有传递依赖关系。
mysql> create table my_order1( -> order_id int primary key, -> customer_id int, -> product_id int, -> customer_tel varchar(15) -> );
在上述这张表中,通过order_id可以知道customer_id,也可以知道customer_tel,但是通过customer_id没准也可以知道customer_tel,所以,这张表中出现了关系冗余。
修改之后:
mysql> create table my_order1( -> order_id int primary key, -> customer_id int, -> product_id int -> ); mysql> create table customer1( -> customer_id int primary key, -> customer_name varchar(20), -> customer_tel varchar(15) -> );