如何更新主键

Sla*_*isa 25 sql-server foreign-keys sql-server-2008 composite-primary-key

这是我的问题:我有2个表:

  1. WORKER,带有列|ID|OTHER_STAF|,其中ID是主键
  2. FIRM,带有列|FPK|ID|SOMETHING_ELSE|,其中组合FPK和ID构成主键,ID也是引用WORKER.ID的外键(不为null,并且必须具有与WORKER中相同的值).

我想创建存储过程UPDATE_ID_WORKER,我希望在WORKER中更改特定ID的值,以及在FIRM中更改ID的特定值的所有实例.

存储过程:

........ @ID .. ????........

kev*_*ers 32

你不应该真的这样做,而是插入一个新的记录,并以这种方式更新它.
但是,如果您真的需要,您可以执行以下操作:

  • 暂时禁用强制执行FK约束(例如ALTER TABLE foo WITH NOCHECK CONSTRAINT ALL)
  • 然后更新你的PK
  • 然后更新您的FK以匹配PK更改
  • 最后启用强制执行FK约束

  • 这将"奏效",但仍然是一个非常糟糕的主意**.当其他用户更改数据时,您不仅会禁用您的FK,而且这将支持糟糕的设计.有一天,下一个开发这个数据库的开发人员会询问(这里是SO)如何解决这个PK更新问题. (36认同)
  • 对于需要完成此任务的人来说,这是一个很好的答案。但值得展示如何禁用和重新启用约束的示例 (3认同)

Per*_*DBA 24

首先,我们选择稳定(非静态)数据列来形成主键,正是因为更新关系数据库中的键(其中引用是按键)是我们希望避免的.

  1. 对于这个问题,密钥是否为关系密钥("由数据组成")并不重要,因此具有关系完整性,功率和速度,或者如果"密钥"是记录ID,则没有关系完整性,权力和速度.效果是一样的.

  2. 我说明了这一点,因为无知的帖子有很多帖子,他们认为这就是记录ID在某种程度上优于关系密钥的确切原因.

  3. 关键是,密钥或记录ID将迁移到需要引用的任何位置.

其次,如果您必须更改密钥或记录ID的值,那么您必须更改它.这是符合OLTP标准的方法.请注意,高端供应商不允许"级联更新".

  • 写一个过程.Foo_UpdateCascade_tr @ID,其中Foo是表名

  • 开始交易

  • 首先使用新的Key或RID值从旧行中INSERT-SELECT父表中的新行

  • 其次,对于所有子表,从上到下工作,使用新的Key或RID值从旧行INSERT-SELECT新行

  • 第三,删除具有旧Key或RID值的子表中的行,从下到上工作

  • 最后,删除父表中具有旧Key或RID值的行

  • 提交交易

重新解决其他问题

其他答案不正确.

  • 在UPDAT所需的行(父级加所有子级)之后禁用约束然后启用它们,如果他们希望继续使用,则不是某人在在线生产环境中可以做的事情.该建议适用于单用户数据库.

  • 需要更改密钥或RID的值并不表示设计缺陷.这是一个普通的需要.通过选择稳定(非静态)键可以减轻这种影响.它可以减轻,但不能消除.

  • 代替自然密钥的代理人不会有任何区别.在您给出的示例中,"密钥"是代理.它需要更新.

    • 请,只是代理,没有"代理键"这样的东西,因为每个词都与另一个词相矛盾.它是一个密钥(由数据组成)xor它不是.代理不是由数据组成的,而是明确的非数据.它没有Key的属性.
  • 关于级联所有必需的更改没有什么"棘手".请参阅上面给出的步骤.

  • 宇宙变化无法阻止任何事情发生.它改变.处理它.由于数据库是有关Universe的事实的集合,因此当Universe发生更改时,数据库将不得不更改.那就是大城市的生活,不是新玩家.

  • 结婚和刺猬被埋葬的人不是问题(尽管这些例子被用来表明这一个问题).因为我们不使用Names作为键.我们使用小而稳定的标识符,例如用于标识Universe中的数据.

    • 名称,描述等在一行中存在一次.密钥存在于迁移的任何位置.如果"密钥"是RID,那么RID也存在于迁移的任何地方.
  • 不要更新PK!是我在一段时间内读过的第二个最热闹的东西. 添加新列是最多的.

  • 您说_高端供应商不允许“级联更新” _,但是在适当的情况下这不是完美的方案吗?我认为这些答案中描述的复杂的多步骤过程比依赖“级联更新”更危险,更容易出错。如果确实偏执,是否可以临时添加“层叠更新”约束,然后更改密钥,然后删除约束?这将始终确保引用完整性,并简化流程。 (2认同)

pbe*_*tje 13

如果您确定此更改适合您正在使用的环境:将辅助表上的FK条件设置为UPDATE CASCADING.

例如,如果将SSMS用作GUI:

  1. 右键单击键
  2. 选择修改
  3. 折叠'INSERT AND UPDATE specific'
  4. 对于"更新规则",选择"级联".
  5. 关闭对话框并保存密钥.

然后,当您更新主表中PK列中的值时,将更新其他表中的FK引用以指向新值,从而保持数据完整性.

  • @Cito:标识列与主键不同,尽管可以选择标识列作为表的主键。您的错误与尝试更新主键无关-这是尝试更新标识列的错误。 (2认同)

Dan*_*ite 5

不要更新主键。如果您有任何其他表引用它,它可能会给您保持数据完整带来很多问题。

理想情况下,如果您想要一个可更新的唯一字段,请创建一个新字段。


KM.*_*KM. 5

当您发现有必要更新主键值以及所有匹配的外键时,则需要修复整个设计.

级联所有必要的外键更改很棘手.从不更新主键是最佳做法,如果您认为有必要,则应使用a Surrogate Primary Key,这是不是从应用程序数据派生的密钥.因此,它的价值与业务逻辑无关,永远不需要改变(并且对最终用户来说应该是不可见的).然后,您可以更新并显示其他一些列.

例如:

BadUserTable
UserID     varchar(20) primary key --user last name
other columns...
Run Code Online (Sandbox Code Playgroud)

当您创建许多具有FK到UserID的表时,要跟踪用户已经处理的所有内容,但该用户随后结婚并希望ID与其新姓相匹配,那么您运气不佳.

GoodUserTable
UserID    int identity(1,1) primary key
UserLogin varchar(20) 
other columns....
Run Code Online (Sandbox Code Playgroud)

您现在将所有其他表的代理主键FK,并在必要时显示UserLogin,允许它们使用该值登录,并且当需要更改它时,只在一行的一列中更改它.