Sql 将不同表中的多个int主键转换为标识

Sql 将不同表中的多个int主键转换为标识,sql,sql-server,Sql,Sql Server,我有十几个类似结构的不同数据库,每个数据库大约有50个不同的表,其中一些表使用顺序int[Id]作为主键和标识 在某个时候,这些数据库被迁移到不同的远程基础设施,即从Azure迁移到AWS,在迁移过程中的某个地方,Identity属性丢失,因此,新的自动插入无法工作,因为它无法自动增加Id并生成有效的主键 我已经尝试了多种解决方案,但我正在努力让它们中的任何一种正常工作,因为SQL Server似乎非常挑剔,让您以任何方式扰乱或改变标识列的值,这让我发疯 我需要在多个不同的表、多个数据库中重新启

我有十几个类似结构的不同数据库,每个数据库大约有50个不同的表,其中一些表使用顺序int[Id]作为主键和标识

在某个时候,这些数据库被迁移到不同的远程基础设施,即从Azure迁移到AWS,在迁移过程中的某个地方,Identity属性丢失,因此,新的自动插入无法工作,因为它无法自动增加Id并生成有效的主键

我已经尝试了多种解决方案,但我正在努力让它们中的任何一种正常工作,因为SQL Server似乎非常挑剔,让您以任何方式扰乱或改变标识列的值,这让我发疯

我需要在多个不同的表、多个数据库中重新启用标识,但我发现的解决方案要么极其复杂,要么不切实际,因为这似乎是一个相对简单的问题

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语句有问题,我需要确保新的values Identity列与旧的Id列具有相同的值,但此方法目前不起作用,因为:

无法更新标识列“Id\u new”


该脚本中有一些假设,您可能希望通过假设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

不添加标识,而是创建和默认约束

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)

您是否使用了
设置标识\u insert off
?我尝试过,是的。它仍然不能解决我的问题,因为它要求我删除行并再次添加它们,同时在执行插入时分别命名每一列。这种方法非常耗时,因为我正在处理许多表和数据库,除非我遗漏了什么。使用例如
sys.columns
,为insert语句生成列列表非常容易。identity属性不像翻转开关那么简单。没有简单的按钮可以让int列的identity属性设置为true。您将不得不一次只处理一个表。尝试并自动执行此操作是一个混乱的过程,尤其是如果您有外键的话。