更新复合主键

3

我正在为是否在我的SQL Server数据库中使用复合主键而进行哲学讨论。过去,我总是使用代理键,现在我正在挑战自己离开我的舒适区尝试不同的东西。我已经阅读了许多讨论,但仍然无法得出任何解决方案。我遇到的问题是当我必须更新具有复合主键的记录时。

例如,要更新的记录如下:

ContactID, RoleID, EffectiveDate, TerminationDT

在这种情况下,PK是(ContactID, RoleID, EffectiveDate)。TerminationDT可以为null。
如果在我的UI中,用户更改了RoleID,那么我需要更新记录。使用代理键,我可以执行Update Table Set RoleID = 1 WHERE surrogateID = Z。然而,使用组合键的方式,一旦组合键中的任何一个字段发生变化,我就无法引用旧记录进行更新,除非现在在UI中维护对旧值的引用。
我不在UI中绑定数据源。我打开一个连接,获取数据并将其存储在桶中,然后关闭连接。大家有什么意见?谢谢。
3个回答

4

通过引用“旧记录”等概念所表达的意思是,关系具有复合键元素之外的语义含义。事实上,你需要一个键来引用旧记录,这意味着复合键元素不足以满足需求。当然,你仍然需要维护外键,但我认为很明显你需要一个主键,而它并不是通常意义上的代理键。

在我看来,可以毫无顾虑地使用代理键。


+1. 在我看来,主键必须是不可变的——一旦你为它分配了值,它就永远不会改变。如果它发生了改变,那么它就不再是主键了。 - Alexander Malakhov
这正是我反对在这种情况下使用复合主键的想法。感谢您的证明! - VBCSharp

1

你走在正确的道路上,但是看着你的主键,我建议你研究一下normalization。我认为你应该尽量避免使用复合键,而是在每个表中使用一个主键,除非必要。例如,你可以将RoleID作为一个单独的表,包含角色描述和其他定义角色的信息,并将其作为外键引用到其他表中。


我想我应该再解释清楚一点。ContactID和RoleID是外键。其中,ContactID是Contact表的主键,而RoleID是Role表的主键。 - VBCSharp

1

首先是简单的部分:

看起来你的表是一个交叉引用,对吧?在这种情况下,我发现组合键非常有效,但前提是,如果你的用户界面和其他库支持它们的话。现在许多用户界面不支持,而且似乎你的也不支持。因此:

1) 对于交叉引用,使用组合键是正确的,这是为数不多的总是有意义的地方之一,但:

2) 如果将一个代理键放入其中会使编码变得更加容易,请务必在这些三个列上添加一个唯一限制。

进一步说,你可能需要一个检查约束条件,以确保日期范围没有重叠,因为数据库不原生支持“范围主键”,这似乎是你正在做的事情。

既然如此,让我再更混淆一些东西。你为什么要更新这一行呢?难道正确的操作不应该是在原始数据上放置终止日期,并强制创建一个新的行,指示联系人的新角色吗?在这种情况下,你可能会保留组合键,并稍微修改用户界面以允许/禁止某些操作。


从用户的角度考虑(哇!),假设用户在原始输入中犯了一个错误,必须返回并更改角色,因为它是不正确的?在完美的世界里,旧角色将过期,新角色将在任期日期之后开始。我可以强制用户删除不正确的记录并输入一个新的正确记录,这是我在UI中考虑过的。日期的验证(无重叠)发生在UI中。 - VBCSharp
嘿,在考虑用户时不要惊讶,如果我能让我的程序员这样做就好了 :) 我猜你必须决定如果用户需要删除/插入数据的话,这有多大的影响。任何用户都会很快发现他们无法更改它,然后他们会将其删除。这真的取决于你对用户群体的了解程度。 - Ken Downs
@VBCSharp:“验证 <...> 发生在 UI 中”,每当我在 DB 数据完整性的背景下听到这句话时,我就会非常怀疑。 - Alexander Malakhov
可疑?我宁愿在调用数据库之前验证用户输入并让数据库抛出错误来防止重叠日期进入数据库。话虽如此,数据库上也有约束条件,如果某些东西通过UI的验证过程,也会防止日期重叠。 - VBCSharp
@VBCSharp:那对我来说没问题。我经常在UI中复制约束以避免DB异常。 - Alexander Malakhov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接