我有十几个结构相似的不同数据库,每个数据库约有50个不同的表,其中一些表使用顺序的int [Id]作为主键和标识。
有时,这些数据库已迁移到另一个远程基础结构,即从Azure迁移到AWS,在此过程中的某个位置丢失了Identity属性,因此,新的自动插入无法正常工作,因为它无法自动执行-递增ID并生成有效的主键。
我尝试了多种解决方案,但都在努力使它们中的任何一种都起作用,因为SQL-Server似乎极其挑剔,让您以任何方式弄乱或更改Identity列的值,这使我发疯。 / p>
我需要在多个数据库的多个表中重新启用Identity,但是到目前为止,我发现的解决方案要么是费解的,要么是不切实际的,因为这似乎是一个相对简单的问题。
tl; dr-如何为多个不同表中的所有int主键同时启用身份?
到目前为止我的方法:
CREATE PROC Fix_Identity @tableName varchar(50)
AS
BEGIN
IF NOT EXISTS(SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(object_id) = @tableName)
BEGIN
DECLARE @keyName varchar(100) = 'PK_dbo.' + @tableName;
DECLARE @reName varchar(100) = @tableName + '.Id_new';
EXEC ('Alter Table ' + @tableName + ' DROP CONSTRAINT ['+ @keyName +']');
EXEC ('Alter Table ' + @tableName + ' ADD Id_new INT IDENTITY(1, 1) PRIMARY KEY');
EXEC ('SET IDENTITY_INSERT [dbo].[' + @tableName + '] ON');
EXEC ('UPDATE ' + @tableName + ' SET [Id_new] = [Id]');
EXEC ('SET IDENTITY_INSERT [dbo].[' + @tableName + '] OFF');
EXEC ('Alter Table ' + @tableName + ' DROP COLUMN Id');
EXEC sp_rename @reName, 'Id', 'Column';
END
END;
我尝试创建此过程,每个表只执行一次,但是UPDATE语句存在问题,我需要保证新值Identity列的值与旧ID列的值相同,但是这种方法目前不起作用,因为:
无法更新标识列“ Id_new”。
答案 0 :(得分:1)
在该脚本中有一些假设,您可能希望通过假设PK约束名称来特别注意。您可能想要在所有表上再次进行检查。脚本的其余部分对我来说似乎很有意义,除了更新新列中的数据后需要重新设置索引的种子之外。
看看是否有帮助:
select t.name AS [Table],c.Name AS [Non-Indent PK],i.name AS [PK Constraint]
from sys.columns c
inner join sys.tables t On c.object_id=t.object_id
inner join sys.indexes i ON i.object_id=c.object_id
AND i.is_primary_key = 1
INNER JOIN sys.index_columns ic ON i.object_id=ic.object_id
AND i.index_id = ic.index_id
AND ic.column_id=c.column_id
WHERE c.Is_Identity=0
答案 1 :(得分:1)
创建sequence和默认约束,而不是添加身份
declare @table nvarchar(50) = N'dbo.T'
declare @sql nvarchar(max) = (N'select @maxID = max(Id) FROM ' + @table);
declare @maxID int
exec sp_executesql @sql, N'@maxID int output', @maxID=@maxID OUTPUT;
set @sql = concat('create sequence ', @table, '_sequence start with ', @maxID + 1, ' increment by 1')
exec(@sql)
set @sql = concat('alter table ', @table, ' add default(next value for ', @table, '_sequence) for ID ')
exec(@sql)