三个相关表的数据库表设计重构
Posted
技术标签:
【中文标题】三个相关表的数据库表设计重构【英文标题】:Database Table Design Restructuring for three related tables 【发布时间】:2021-10-25 02:31:58 【问题描述】:我有三个表需要像这样链接:
Event(RiskID) -> Risk(RiskID)
Risk(ProjectID) -> Project(ProjectID)
Event(ProjectID) -> Project(ProjectID)
使用这些表格:
项目表
+------------+-----------+
| ID | ProjectID |
+------------+-----------+
以及我试图通过外键约束链接的底部两个表
风险
+------------+-----------+------------+
| ID | ProjectID | RiskID |
+------------+-----------+------------+
事件(又名风险缓解事件,每个风险有很多事件,每个项目有很多风险)
+------------+-----------+------------+-------+
| ID | ProjectID | EventID | RiskID|
+------------+-----------+------------+-------+
根据我目前对 mysql 等关系数据库的理解,要创建外键,我应该在需要引用值的表的链接表中使用一个主键,并强制执行引用完整性。如果所有三个表都具有重复值,即属性集 ProjectID,EventID 是因为我的所有表都具有特定于历史记录的列信息来跟踪更改,我该如何实现此约束?
这种做法让我对在这种情况下必要时如何创建外键产生了一些疑问。如何在外键中使用 ID,但仍将 ProjectID, EventID ProjectID, RiskID 一起使用...等等...
如果我的术语与所理解的有偏差,我可以修改或澄清。希望我的问题(关于外键的这个话题)有一个共同的解决方案?
【问题讨论】:
为什么表 risk 有 ID 和 RiskId ? 通常只有一个id所以id =event_id。如果一个项目可能有很多风险,那么您需要一个桥接表 @Raphael, Id 是该表的唯一键,因为我在附加列中非破坏性地添加具有所采取操作(创建、更新、删除)的记录,以记录历史上下文和特定用户执行的操作 @nbk,我删除了我的桥接实体评论,但我对这种方法有一个想法 声明一个 FK 告诉 DBMS 某处的子行值在其他地方显示为 UNIQUE。如果不是这样,您为什么要声明 FK? (修辞。)你没有解释你想要什么或为什么或如何被卡住。您的“理解”和目标/问题没有被清楚地描述并且似乎被误解了。遵循已发布的信息建模和数据库设计参考/教科书,并提出 1 个经过研究的特定非重复问题,以了解您是如何第一次陷入困境/不确定的。 【参考方案1】:我会添加几个桥表,这样每个项目 kann 都会有很多风险和多极事件
我不太清楚为什么你有另一个主唯一键,但是好的 evrybiody 可以做他们喜欢做的事
每一列应该只有一个
项目
Proj_IG(PK) | Project_ID(KEY)
event_project
Project_ID(FK) | Envent_ID(FK
事件
Evnt_ID | Envent_ID....._
如果事件项目和风险是相互关联的,你可以制作一个三列的桥表,那么一个项目也可以同时包含多个事件和风险,但它们都被连接起来,桥表代表那个
风险项目
RIsk_ID Projekt_ID
风险
R_ID | Risk_ID
项目
Proj_IG(PK) | Project_ID(KEY)
event_risk 项目
Project_ID(FK) | Envent_ID(FK) | Risk_ID(FK)
事件
Evnt_ID | Envent_ID....._
风险
R_ID | Risk_ID
【讨论】:
感谢您的有用建议,我需要将我的问题限制在数据库设计上,这是我最大的不确定性,主要是针对此线程,但规范化我现有的表是另一个已涵盖的问题。在我决定向每个表添加历史上下文之前,键(每个表的 ID)就在那里。谢谢!【参考方案2】:外键不需要指向主键
如果您确实想为非主键创建外键,则它必须是对其具有唯一约束的列。
这个线程更明确一点 Foreign Key to non-primary key
【讨论】:
这就是我的想法,因此,我的设计依赖于双箭头链接,列需要在约束中,这是我的第一个也是主要的模糊点【参考方案3】:Event.ProjectID
是多余的,违反了第三范式。由于给定的风险仅引用了一个项目,因此如果您引用了一个项目,那么您可以在事件表中创建一个异常,然后又引用一个不同的项目的风险。事件真正属于哪个项目变得模棱两可。
看起来您在每个表中都有一个多余的 ID。 Project.Id 和 Project.ProjectId 有什么区别? Risk.ProjectId 应该参考哪一个? Project.ProjectId 是否有唯一约束?
如果可能的话,通常您只会为每个表创建一个唯一键,并且它将作为主键。
所以你最终会得到这样的结果:
Event(RiskID) -> Risk(RiskID)
Risk(ProjectID) -> Project(ProjectID)
项目
+----------------+
| ProjectID (PK) |
+----------------+
风险
+--------------+----------------+
| RiskID (PK) | ProjectID (FK) |
+--------------+----------------+
活动
+---------------+-------------+
| EventID (PK) | RiskID (FK) |
+---------------+-------------+
【讨论】:
当我退后一步时,我认为我可能会违反传递依赖要求。在我的情况下,我什么时候不需要使用像 id 这样的非必要列?也许我应该问在这个例子中使用像我的 3 个表这样的历史记录时是否应该使用密钥。 就我而言,我没有考虑到的异常是否意味着我正在以违反实体完整性的方式改变事件的值?我的 id 是一个唯一的自动递增值,我有一个添加模式,在我的例子中 ProjectID 是重复的,因为我在所有三个表中都有一个名为 IsHistory 的列来存储对表的更改记录。每个表的 ID 始终是唯一的(每个表本质上是一个当前值持有者和历史日志) 我可能会选择将历史记录存储在单独的表中,因此 Project 表只存储当前状态。如果您在 Project 中使用相同的 ProjectId 值存储多行,则无法在 ProjectId 上声明唯一键。这很重要,因为外键应该只引用一个唯一的行。 My RiskID 用于向用户显示每个项目的友好顺序 ID,例如风险 1-5 进入项目 1,风险 1-5 进入项目 2,但主 ID仍然是独一无二的,如果需要的话 那么听起来RiskId
会有重复。好吧,您可以改为引用自动增量Id
。但是外键应该引用主键或唯一键。以上是关于三个相关表的数据库表设计重构的主要内容,如果未能解决你的问题,请参考以下文章