一句话核心思想
第二范式就是:一张表只干一件事。
更专业一点说:确保表中的每列都完全依赖于整个主键,而不是只依赖于主键的一部分。
用一个生动的例子来解释
想象一下,我们有一张 订单明细表
来记录超市的购物小票。
订单ID (主键) | 商品ID (主键) | 商品名称 | 单价 | 数量 | 顾客姓名 | 顾客电话 |
---|---|---|---|---|---|---|
1001 | A01 | 可口可乐 | 3.5 | 2 | 张三 | 13800138000 |
1001 | B02 | 乐事薯片 | 8.0 | 1 | 张三 | 13800138000 |
1002 | A01 | 可口可乐 | 3.5 | 5 | 李四 | 13900139000 |
这张表有什么问题?(它违反第二范式)
-
冗余重复:
-
同一个订单ID(1001)出现了两次,顾客“张三”和他的电话也被重复存储了。
-
商品“可口可乐”的单价(3.5)在多个订单中重复出现。如果可乐涨价了,我们需要修改表中所有包含了“A01”商品的行,非常容易出错和遗漏。
-
-
更新异常:
-
如果张三换了手机号,我必须找到所有
订单ID=1001
的记录,一条一条地去修改顾客电话
,而不能只修改一次。
-
-
插入异常:
-
如果有一个新商品“C03-农夫山泉”刚刚入库,但还没有任何订单购买过它,我们就无法把这个商品的信息(名称、单价)插入到这张表里。因为缺少主键的另一部分(订单ID)。
-
-
删除异常:
-
如果订单1001的“乐事薯片”这条记录被删除了,我们可能就彻底丢失了“张三”这个顾客的信息,因为他只有一个订单。
-
为什么会这样?
因为这张表不止干了一件事!它混杂了:
-
订单的详细信息(哪个订单买了哪个商品,买了多少)
-
商品自身的信息(商品叫什么,卖多少钱)
-
顾客的信息(谁买的,联系方式)
它的主键是(订单ID, 商品ID)
,这是一个联合主键。
-
数量
完全依赖于整个主键(我必须同时知道订单号和商品号,才能确定买了几件)。 -
但是
顾客姓名
和顾客电话
只依赖于订单ID
。只要我知道订单号1001,我就知道顾客是张三,不需要知道商品ID是什么。 -
同样,
商品名称
和单价
只依赖于商品ID
。只要我知道商品ID是A01,我就知道它是可口可乐,价格3.5元,不需要知道是哪个订单买的。
这种“只依赖于部分主键”的列,就是违反第二范式的根源。
如何改造?(使其符合第二范式)
核心操作:拆表!让每张表只干一件事。
我们把上面那张大杂烩表拆成三张表:
1. 订单表 (专门管订单和顾客的关系)
订单ID (主键) | 顾客姓名 | 顾客电话 |
---|---|---|
1001 | 张三 | 13800138000 |
1002 | 李四 | 13900139000 |
2. 商品表 (专门管商品信息)
商品ID (主键) | 商品名称 | 单价 | |
---|---|---|---|
A01 | 可口可乐 | 3.5 | |
B02 | 乐事薯片 | 8.0 | |
C03 | 农夫山泉 | 2.0 | (新商品可以独立添加了!) |
3. 订单明细表 (专门管订单买了什么商品)
订单ID (联合主键) | 商品ID (联合主键) | 数量 |
---|---|---|
1001 | A01 | 2 |
1001 | B02 | 1 |
1002 | A01 | 5 |
改造后的好处:
-
数据冗余大大减少:顾客信息只存一次,商品信息只存一次。
-
避免更新异常:张三换手机号,只需在
订单表
里修改一次。可乐涨价,只需在商品表
里修改一次。 -
避免插入异常:新商品“农夫山泉”可以直接添加到
商品表
,哪怕它还没被卖出过。 -
避免删除异常:即使删除了订单1001的薯片记录,张三的信息依然安全地保存在
订单表
里。
总结:如何判断和满足第二范式?
-
第一步:确保你的表已经满足了第一范式(每个字段都是不可再分的原子值)。
-
第二步:看看你的表有没有联合主键(由多个字段组成的主键)。
-
第三步:检查表中的每一个字段,问自己:
“这个字段是完全依赖于整个主键,还是只依赖于主键中的一部分?”
-
第四步:如果发现只依赖于部分主键的字段,就把它们拆出去,放到另一张表里,并为它们建立新的主键。
最终记住那个简单的比喻:一个好的数据库设计就像一个好的公司架构,每个部门(表)职责单一,专业高效,而不是一个部门什么都管,混乱不堪。
来源链接:https://www.cnblogs.com/zp123456/p/19049977
没有回复内容