我正在努力讨论是否在我的SQL Server数据库上使用复合主键的哲学讨论。我过去总是使用代理键,我正在挑战自己离开我的舒适区尝试不同的东西。我已经阅读了很多讨论,但还没有找到任何解决方案。我遇到的困难是我必须使用复合PK更新记录。
例如,问题中的记录是这样的:
ContactID, RoleID, EffectiveDate, TerminationDT
这种情况下的PK是(ContactID, RoleID, EffectiveDate)
。 TerminationDT
可以为null。
如果在我的用户界面中,用户更改了RoleID
,那么我需要更新记录。使用代理键我可以Update Table Set RoleID = 1 WHERE surrogateID = Z
。但是,使用Composite Key方式,一旦复合键中的一个字段发生更改,我就无法引用旧记录来更新它,而现在不在UI中的某处维护对旧值的引用。
我没有在我的UI中绑定数据源。我打开一个连接,获取数据并将其存储在存储桶中,然后关闭连接。每个人的意见是什么?感谢。
答案 0 :(得分:4)
通过引用诸如“旧记录”之类的想法,您所说的是该关系具有独立于复合关键元素的语义含义。您需要一个键来引用旧记录这一事实意味着复合键元素是不够的。当然,你仍然保留外键,但我似乎很清楚你需要一个主键,并且它不是通常意义上的代理键。
在我看来,使用代理密钥无罪。
答案 1 :(得分:1)
你走在正确的轨道上,但是看着你的主键,我建议你看看normalization。我认为您应该尝试远离使用复合键,并尝试每个表使用一个主键,除非必要。例如,您可以使用RoleID,并将其作为自己的表,包含角色描述,以及其他任何定义角色的内容,并将其作为外键引用放在其他表中。
答案 2 :(得分:1)
首先是简单的部分:
看起来你的桌子是交叉引用,不是吗?在这种情况下,我发现复合键工作得非常好,IF,这是一个很大的IF,如果您的UI和其他库了解它们。现在很多用户界面都没有,听起来你的用户没有。因此:
1)使用复合键进行交叉引用是正确的,这是它总是有意义的少数几个地方之一,但是:
2)如果它可以使代码的其余部分更容易,那么您也可以在其中放置代理键,但是记得在这三列上添加唯一约束。
更进一步,您可能需要一个检查约束,以确保日期范围内没有重叠,因为数据库本身不支持“范围主键”,这就像您正在做的那样。
现在有了这样说,让我进一步混淆。你为什么要更新这一行?正确的操作是不是在原始文件上设置终止日期并强制创建表示联系人新角色的新行?在这种情况下,您可能会保留复合并使UI略微允许/禁止某些操作。