我需要将一个表的主键更改为一个标识列,并且在表中已经有许多行。

我有一个脚本来清理id,以确保它们从1开始是顺序的,在我的测试数据库上运行良好。

更改列以具有标识属性的SQL命令是什么?


当前回答

这里有一个很酷的解决方案: 在列上添加或删除标识属性

简而言之,在SQL管理器中手动编辑您的表,切换标识,不要保存更改,只显示将为更改创建的脚本,复制它并稍后使用。

这节省了大量的时间,因为它(脚本)包含了所有与您更改的表相关的外键、索引等。手动写这个…上帝保佑。

其他回答

As I understood in normal cases we are creating a table with Primary key which is having Identity property So Rename or Delete a column which is associated with Primary Key constraint will not be possible because constraint Rules are validating column structure. Tto achieve this we have to process some steps in the following way: Let us assume TableName = 'Employee' and ColumnName = 'EmployeeId' 1. Add new column 'EmployeeId_new' in the 'Employee' table ALTER TABLE Employee ADD EmployeeId_new INT IDENTITY(1,1)

Now remove column 'EmployeeId' from 'Employee' table ALTER TABLE Employee DROP COLUMN EmployeeId This will throw error because of Primary Key Constraint rules are applicable and validating column structure. *### 'Msg 5074, Level 16, State 1, Line 1 The object [PK_dbo.Employee] is dependent on colmn [EmployeeId].'### So we have to remove the Primary Key constraint first from the table 'Employee' then we can remove the column ALTER TABLE Employee DROP constraint [PK_dbo.Employee] Now we can remove the column 'EmployeeId' from 'Employee' table as did in the previous step where we got error ALTER TABLE Employee DROP COLUMN EmployeeId Now Column 'EmployeeId' removed from table So we will Rename the newly added new column 'EmployeeId_new' with 'EmployeeId' sp_rename 'Employee.EmployeeId', 'EmployeeId_new', 'COLUMN' To rearrange the table in the same form as It was, we have to add Primary Key Constraint for the column 'EmployeeId' ALTER TABLE Employee add constraint [PK_dbo.Employee] primary key (EmployeeId)

8. 现在,带有'EmployeeId'的表'Employee'随着现有的主键约束被修改为Identity规则

根据我目前的情况,我采用这种方法。我想通过脚本插入数据后给一个主表的身份。

因为我想要追加身份,所以它总是从1开始到我想要的记录计数的结束。

--first drop column and add with identity
ALTER TABLE dbo.tblProductPriceList drop column ID 
ALTER TABLE dbo.tblProductPriceList add ID INT IDENTITY(1,1)

--then add primary key to that column (exist option you can ignore)
IF  NOT EXISTS (SELECT * FROM sys.key_constraints  WHERE object_id = OBJECT_ID(N'[dbo].[PK_tblProductPriceList]') AND parent_object_id = OBJECT_ID(N'[dbo].[tblProductPriceList]'))
    ALTER TABLE [tblProductPriceList] ADD PRIMARY KEY (id)
GO

这将创建具有identity的相同主键列

我使用了这个链接:https://blog.sqlauthority.com/2014/10/11/sql-server-add-auto-incremental-identity-column-to-table-after-creating-table/

向现有表添加主键

您不能更改现有列的标识。

你有两个选择,

创建一个带有标识的新表并删除现有表 创建一个具有标识的新列并删除现有列

方法1。(新表)在这里,您可以保留新创建的标识列上的现有数据值。请注意,如果不满足'if not exists',您将丢失所有数据,因此请确保您将条件也放在drop上!

CREATE TABLE dbo.Tmp_Names
    (
      Id int NOT NULL
             IDENTITY(1, 1),
      Name varchar(50) NULL
    )
ON  [PRIMARY]
go

SET IDENTITY_INSERT dbo.Tmp_Names ON
go

IF EXISTS ( SELECT  *
            FROM    dbo.Names ) 
    INSERT  INTO dbo.Tmp_Names ( Id, Name )
            SELECT  Id,
                    Name
            FROM    dbo.Names TABLOCKX
go

SET IDENTITY_INSERT dbo.Tmp_Names OFF
go

DROP TABLE dbo.Names
go

Exec sp_rename 'Tmp_Names', 'Names'

方法2(新列)不能在新创建的标识列上保留现有数据值,标识列将保留数字序列。

Alter Table Names
Add Id_new Int Identity(1, 1)
Go

Alter Table Names Drop Column ID
Go

Exec sp_rename 'Names.Id_new', 'ID', 'Column'

请参阅以下Microsoft SQL Server论坛帖子了解更多细节:

如何将列更改为identity(1,1)

基本上有四个逻辑步骤。

创建一个新的Identity列。为这个新列打开Insert Identity。 将源列(希望转换为Identity的列)中的数据插入到这个新列中。 关闭新列的Insert Identity。 删除源列并将新列重命名为源列的名称。

可能会有一些更复杂的事情,比如跨多个服务器工作等。

有关步骤(使用ssms和T-sql),请参阅下面的文章。这些步骤适用于不太熟悉T-SQL的初学者。

http://social.technet.microsoft.com/wiki/contents/articles/23816.how-to-convert-int-column-to-identity-in-the-ms-sql-server.aspx

在SQL 2005及以上版本中,有一个技巧可以在不改变表的数据页的情况下解决这个问题。这对于大型表很重要,因为在这些表中,处理每个数据页可能需要花费几分钟或几小时的时间。即使标识列是一个主键,是聚集或非聚集索引的一部分,或者其他可能阻碍更简单的“添加/删除/重命名列”解决方案的陷阱,这个技巧也同样有效。

这里有一个技巧:你可以使用SQL Server的ALTER TABLE…SWITCH语句在不改变数据的情况下更改表的模式,这意味着您可以使用相同的表模式替换IDENTITY表,但没有IDENTITY列。同样的技巧也适用于向现有列添加IDENTITY。

通常,ALTER TABLE…SWITCH用于有效地将分区表中的满分区替换为新的空分区。但它也可以用于非分区表。

我使用这个技巧在不到5秒的时间内将一个25亿行表中的列从IDENTITY转换为非IDENTITY(为了运行一个多小时的查询,其查询计划对非IDENTITY列更有效),然后在不到5秒的时间内恢复IDENTITY设置。

下面是它如何工作的代码示例。

 CREATE TABLE Test
 (
   id int identity(1,1),
   somecolumn varchar(10)
 );
  
 INSERT INTO Test VALUES ('Hello');
 INSERT INTO Test VALUES ('World');
  
 -- copy the table. use same schema, but no identity
 CREATE TABLE Test2
 (
   id int NOT NULL,
   somecolumn varchar(10)
 );
  
 ALTER TABLE Test SWITCH TO Test2;

 -- drop the original (now empty) table
 DROP TABLE Test;

 -- rename new table to old table's name
 EXEC sp_rename 'Test2','Test';
  
 -- update the identity seed
 DBCC CHECKIDENT('Test');

 -- see same records
 SELECT * FROM Test; 

这显然比其他答案更复杂,但如果您的表很大,这可能是一个真正的救星。这里有一些注意事项:

As far as I know, identity is the only thing you can change about your table's columns with this method. Adding/removing columns, changing nullability, etc. isn't allowed. You'll need to drop foriegn keys before you do the switch and restore them after. Same for WITH SCHEMABINDING functions, views, etc. new table's indexes need to match exactly (same columns, same order, etc.) Old and new tables need to be on the same filegroup. Only works on SQL Server 2005 or later I previously believed that this trick only works on the Enterprise or Developer editions of SQL Server (because partitions are only supported in Enterprise and Developer versions), but Mason G. Zhwiti in his comment below says that it also works in SQL Standard Edition too. I assume this means that the restriction to Enterprise or Developer doesn't apply to ALTER TABLE...SWITCH.

TechNet上有一篇很好的文章详细介绍了上述要求。

更新- Eric Wu在下面评论了关于这个解决方案的重要信息。复制在这里,以确保它得到更多的关注:

这里还有一个值得一提的警告。虽然 新表将愉快地从旧表接收数据,并且所有的 新行将按照标识模式插入 从1开始,如果该列是主键,则可能中断。 考虑立即运行DBCC CHECKIDENT('<newTableName>') 切换。详见msdn.microsoft.com/en-us/library/ms176057.aspx 信息。

If the table is actively being extended with new rows (meaning you don't have much if any downtime between adding IDENTITY and adding new rows, then instead of DBCC CHECKIDENT you'll want to manually set the identity seed value in the new table schema to be larger than the largest existing ID in the table, e.g. IDENTITY (2435457, 1). You might be able to include both the ALTER TABLE...SWITCH and the DBCC CHECKIDENT in a transaction (or not-- haven't tested this) but seems like setting the seed value manually will be easier and safer.

显然,如果没有新行被添加到表中(或者它们只是偶尔添加,比如每天的ETL进程),那么这种竞争条件就不会发生,因此DBCC CHECKIDENT是可以的。