为其他表使用的表设计sql表关系的最佳解决方案是什么
我遇到了一个相当有趣的情况,我需要指导来帮助我设计遵循“最佳实践”或“推荐方式”的数据库模式 我的困境如下: 我有一个为其他表使用的表设计sql表关系的最佳解决方案是什么,sql,sql-server,entity-framework,database-design,table-relationships,Sql,Sql Server,Entity Framework,Database Design,Table Relationships,我遇到了一个相当有趣的情况,我需要指导来帮助我设计遵循“最佳实践”或“推荐方式”的数据库模式 我的困境如下: 我有一个事件表,其中包含Id、姓名、日期等基本属性。它需要地址信息,因此最直接的方法是使用街道、城市、国家等字段扩展表。我还有一个用户表,也需要存储地址数据。所以正确的做法是创建第三个名为Address的表,并在Address/User和Address/Event之间建立关系。这是棘手的部分。哪个表应该包含主键/外键 一种方法是使用诸如EventId和UserId等列扩展表Address
事件
表,其中包含Id、姓名、日期等基本属性。它需要地址信息,因此最直接的方法是使用街道、城市、国家等字段扩展表。我还有一个用户表,也需要存储地址数据。所以正确的做法是创建第三个名为Address的表,并在Address/User和Address/Event之间建立关系。这是棘手的部分。哪个表应该包含主键/外键
EventId
和UserId
等列扩展表Address
。因此,表Event
和User
将是“父”表,而address将是“子”表。地址表将保存用户/事件Id主键的外键
|EventTable:| |UserTable: | |AddressTable|
| | | | | |
|EventId PK | |UserId PK | |AddresId PK |
|Name | |Name | |Street |
|OtherColumn| |OtherColumn| |City |
|EventId FK |
|UserId FK |
我从这种设计中看到的两个缺点是,对于每一行AddressTable
,都会包含额外的不必要的空字段。例如,如果地址指定了用户地址,则列EventId
将为Null;如果地址行指定了事件地址,则列UserId
将为Null
第二个缺点是,每当我添加一个也需要连接到地址表的新表时,我都需要向表地址添加另一列,该列将引用新表的主键
Address
的主键列扩展表Event
和User
,使它们成为关系中的外键
|EventTable:| |UserTable: | |AddressTable|
| | | | | |
|EventId PK | |UserId PK | |AddresId PK |
|Name | |Name | |Street |
|OtherColumn| |OtherColumn| |City |
|AddressId FK| |AddressId FK|
使用这个解决方案一切都会很完美,除了我现在对启用外键上的级联删除有疑问。对我来说,一种自然的想法是,当我删除数据库的事件或用户时,我也希望删除他们的地址。但在这种设计中,地址表是父级,用户/事件是子级。所以,当我删除启用级联删除的地址条目时,我也会删除事件/用户条目。从逻辑上讲,这对我来说没什么意义。应该是相反的,这是我无法解决的问题。也许第二种设计是可以接受的,我只是无缘无故地把自己搞糊涂了谢谢 只要在两个FK上保持唯一的约束,关节表仍然是一个选项。然而,第二种选择可能是总体上最好的。为了让deletes按您想要的方式运行,我建议在从EventTable和UserTable删除时设置一个触发器。第二种方法对我来说似乎是最干净的。毕竟,例如,您可能有多个具有相同地址的用户。然而,我应该指出,“事件”地址和“个人”地址是否相同并不清楚。例如,“个人”地址可能有邮政编码,“事件”地址可能描述到达某一地点的不同方式 在任何情况下,您都有反向级联。例如,当你删除一个用户时,你是在向后思考。地址不会发生任何变化。问题是当你从地址中删除某些内容时会发生什么。然后,相应的用户和事件将被删除。级联的目的是在主键更改时保持关系完整性
如果您想在删除用户/事件时删除地址,那么我建议使用触发器。然而,这对于关系完整性来说并不是必需的。地址确实很棘手 首先,地址是一个独立的东西——它的存在超出了你的控制,相反,只要地方议会愿意,它就存在。另一件重要的事情——地址往往会被反复使用,特别是当我们谈论大型活动或短期租赁住宿时 考虑到所有这些,选择1显然是错误的,与现实不相关。第二个更好,但仍然错过了很多,虽然在这种情况下,它更多地取决于你愿意走多远 例如,如果要存储任何类型实体的地址更改历史记录,则需要历史记录表-同样,有几种可能的设计。您可以使用以下字段创建一个地址历史记录表:
AddressId (PK)
TenantId (PK)
StartDate (PK)
EndDate
,其中,TenantId
将引用一个超类型表,该表将成为所有可以使用地址的实体的父级。这样一个表(不是超类型表)也将有助于防止(或允许?)在任何给定时间多个租户同时使用同一地址
这只是冰山一角:)因为你给出的理由,选项1是不可能的 使用选项2,您不必担心未使用的地址记录。事实上,它们在创建新事件或用户时可能会变得有用,因为您可以在地址“数据库”中提供搜索功能。进一步说,您甚至可以决定使用从某个地址提供者下载的数据预填充地址表。那么搜索工具就会变得非常有用 一旦你计划有一个大的地址列表,你可能想把一个地址分成它自己的等级:一条街道属于一个城市,一个城市属于一个国家。当然,在实践中,一条街道可以由多个城市共享,您可以决定建立n对n关系