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