开发中经常遇到一对多的情况,比如博客系统:一个用户可以写多个博文。
那么用户和博文的关系怎么维护,换句话说怎么设计表,你大概会想到以下三种方案:
-
共用户(user)和博文(post)两个表,用户表中有博文字段(posts),存储的是该用户拥有的每个博文的id(同下均代表主键),中间用逗号(',')分隔。
-
共用户(user)和博文(post)两个表,博文表中有用户字段,存储的是用户(作者)的id。
-
共用户(user)、博文(post)和写作关系(user_post)三个表,关系表中任意用户的任一篇博文是一条记录,所以每个用户有几篇博文,对应标准就有几个记录。
第一种方案路子有点野,但是我在一个一期三千万的大项目中也看到过这种设计,不知道是出于特殊考虑还是...,这个设计的缺点很明显,如查询某个博文属于哪个作者是常用的查询,此时只能将所有用户的的所有博文查出来,从中分析和匹配该文章id,费时费力,唯一的好处是比较符合正常的思维习惯。
第二和第三种方式中,你应该一眼就相中了第二种,不但少维护了一个表,数据冗余度也少一些,理解上也更清晰一些:一篇博文只属于一个用户。确实,开发中更倾向于第二种方案。
这里引用王珊、萨师煊老师的《数据库系统概论》里的一段话:
(1)一个1:1联系可以转换为一个独立的关系模式, 也可以与任意一端对应的关系模式合并。如果转换为个独立的关系模式, 则与该联系相连的各实体的码以及联系本身的属性均转换为关系的属性,每个实体的码均是该关系的候选码。如果与某一一端实体对应的关系模式合并,则需要在该关系模式的属性中加入另一个关系模式的码和联系本身的属性。
(2)一个1:n联系可以转换为一个独立的关系模式,也可以与n端对应的关系模式合井。如果转换为个独立的关系模式,则与该联系相连的各实体的码以及联系本身的属性均转换为关系的属性,而关系的码为n端实体的码。
(3)一个m:n联系转换为个关系模式,与该联系相连的各实体的码以及联系本身的属性均转换为关系的属性,各实体的码组成关系的码或关系码的部分。
(4)三个或三个以上实体间的一个多元联系可以转换为一个关系模式。与该多元联系I相连的各实体的码以及联系本身的属性均转换为关系的属性,各实体的码组成关系的码或关系码的一部分。
(5)具有相同码的关系模式可合并。
我结合用户-博文的关系翻一下第二段话,即一对多的情况,其余情况大家自行理解。
一个一对多的实体间的联系可以转化为一个独立的关系模式(用户和博文之间的写作关系),也可以由多方(博文方)来维护两者之间的关系。如果转化为独立的关系模式(创建user_post表),表中的字段包括用户和博文的主键以及写作关系的其他属性(比如写作共用了多长时间),而user_post表的主键应该是多方(博文)的主键。
这里没具体写明“与n端对应的关系模式合井”:事实上,合并后应在n端加入1端关系的码和联系本身的属性,合并后的码保持不变。就是说,在博文表中加入用户的主键和关系相关的字段,博文的主键还是博文的主键没有改变。
网友评论