这远非理想情况,但我需要通过将数字“1”附加到与其他四个表具有 FK 关系的 PK Identiy 列来修复数据库。我基本上是把一个四位数的数字变成一个五位数的数字。我需要维持关系。我可以将数字存储在 var 中,执行 Set 查询并附加 1,然后为每个表执行此操作...
有没有更好的方法来做到这一点?
这远非理想情况,但我需要通过将数字“1”附加到与其他四个表具有 FK 关系的 PK Identiy 列来修复数据库。我基本上是把一个四位数的数字变成一个五位数的数字。我需要维持关系。我可以将数字存储在 var 中,执行 Set 查询并附加 1,然后为每个表执行此操作...
有没有更好的方法来做到这一点?
您说您正在为主键使用identity
数据类型,因此在更新数字之前,您必须SET IDENTITY_INSERT ON
(此处的文档),然后在更新后再次将其关闭。
只要您为关系设置了级联更新,其他表就应该自动更新。
编辑:由于无法更改身份值,我猜您必须导出数据,设置新的身份值(+10000),然后再次导入您的数据。
谁有更好的建议...
我的建议是:
事后改变PK并不好玩。
考虑向 PK 添加另一个字段,而不是延长 PK 字段的长度。您的新字段必须级联到相关表,就像字段长度增加一样,但您可以保留原始 PK 值。
如果有问题的列上有一个标识属性,它就会变得复杂。这或多或少是我的做法:
备份您的数据库。
将其置于单用户模式。在你做手术的时候,你不需要任何人在附近闲逛。
执行ALTER TABLE
必要的语句
克隆你的表,给它一个新的名字和一个列相同的定义。不要为任何触发器、索引、外键或其他约束而烦恼。从表的定义中省略标识属性。
创建一个新的“映射”表,将旧的 id 值映射到新值:
create table dbo.pk_map
(
old_id int not null primary key clustered ,
new_id int not null unique nonclustered ,
)
填充映射表:
insert dbo.pk_map
select old_id = old.id ,
new_id = f( old.id ) // f(x) is the desired transform
from dbo.tableInQuestion old
填充新表,为主键列赋予新值:
insert dbo.tableInQuestion_NEW
select id = map.id ,
...
from dbo.tableInQuestion old
join dbo.pk_map map on map.old_id = old.id
截断原始表:TRUNCATE dbo.tableInQuestion
. 这应该可以安全地工作,因为您已禁用所有触发器和外键约束。
执行SET IDENTITY_INSERT dbo.tableInQuestion ON
。
重新加载原始表:
insert dbo.tableInQuestion
select *
from dbo.tableInQuestion_NEW
执行SET IDENTITY_INSERT dbo.tableInQuestion OFF
执行drop table dbo.tableInQuestion_NEW
。我们都完成了。
执行DBCC CHECKIDENT( dbo.tableInQuestion , reseed )
以使身份计数器与表中的数据重新同步。
现在,使用映射表将更改的主键列向下传播。根据您的 ER 模型,这可能会变得复杂,因为引用更新列的外键本身可能是复合主键的一部分。
完成后,开始重新启用您禁用的约束和触发器。确保使用该WITH CHECK
选项执行此操作。修复因此发现的任何问题。
最后,删除映射表,清除单用户标志并使您的系统重新联机。
小菜一碟!(或者其他的东西。)
考虑这种方法:将身份种子重置为 10000 + 当前种子。设置identity insert on Insert into the table 从表中的值,中途的identity列加10000。前任:
Set identity insert on
Insert Table(identity, column1, eolumn2)
select identity + 10000, column1, column2
From Table
Where identity < origional max identity value
插入后,您知道身份比原来的身份正好多 10000。通过添加 10000 来更新外键。