【问题标题】:Convert multiple int primary keys from different tables into Identity将不同表中的多个int主键转换为Identity
【发布时间】:2018-07-26 05:27:42
【问题描述】:

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

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

我尝试了多种解决方案,但都在努力让它们中的任何一个工作,因为 SQL-Server 似乎非常挑剔,让您以任何方式弄乱或更改 Identity 列的值,这让我发疯了。

我需要在多个不同的表、多个数据库中重新启用身份,但到目前为止,我发现的解决方案要么非常复杂,要么不切实际,因为这似乎是一个相对简单的问题。

tl;dr - 如何同时为多个不同表中的所有 int 主键启用 Identity?

到目前为止我的方法:

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”。

【问题讨论】:

  • 你用过set identity_insert off吗?
  • 我试过了,是的。它仍然不能解决我的问题,因为它需要我删除行并再次添加它们,同时在插入时单独命名每一列。这种方法将非常耗时,因为我正在处理许多表和数据库,除非我遗漏了什么。
  • 使用例如为插入语句生成列列表非常容易。 sys.columns.
  • 身份属性并不像拨动开关那么简单。没有简单的按钮可以让您的 int 列将 identity 属性设置为 true。您将不得不一次处理一张桌子。
  • 尝试自动执行此操作很麻烦,尤其是在您有外键的情况下。

标签: sql sql-server


【解决方案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

【讨论】:

    【解决方案2】:

    创建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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-01
      • 1970-01-01
      相关资源
      最近更新 更多