将来自不同表的多个int主键转换为Identity

时间:2018-07-25 19:59:13

标签: sql sql-server

我有十几个结构相似的不同数据库,每个数据库约有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”。

2 个答案:

答案 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)