如何以编程方式更改标识列值?

时间:2009-04-15 12:43:48

标签: sql-server sql-server-2005 tsql identity sql-server-2005-express

我有一个MS SQL 2005数据库,其中包含TestID列。 ID是一个标识列。

我在这个表中有行,并且所有行都有相应的ID自动递增值。

现在我想更改此表中的每个ID,如下所示:

ID = ID + 1

但是当我这样做时,我收到一个错误:

  

无法更新标识列“ID”。

我试过这个:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

但这并没有解决问题。

我需要将标识设置为此列,但我还需要不时更改值。所以我的问题是如何完成这项任务。

13 个答案:

答案 0 :(得分:217)

你需要

set identity_insert YourTable ON

然后删除您的行并以不同的身份重新插入。

完成插入操作后,请不要忘记关闭identity_insert

set identity_insert YourTable OFF

答案 1 :(得分:40)

IDENTITY列值是不可变的。

但是,可以切换表元数据以删除IDENTITY属性,执行更新,然后切换回来。

假设以下结构

CREATE TABLE Test
(
ID INT IDENTITY(1,1) PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test 
OUTPUT INSERTED.*
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

然后你可以做

/*Define table with same structure but no IDENTITY*/
CREATE TABLE Temp
(
ID INT PRIMARY KEY,
X VARCHAR(10)
)

/*Switch table metadata to new structure*/
ALTER TABLE Test SWITCH TO Temp;

/*Do the update*/
UPDATE Temp SET ID = ID + 1;

/*Switch table metadata back*/
ALTER TABLE Temp SWITCH TO Test;

/*ID values have been updated*/
SELECT *
FROM Test

/*Safety check in case error in preceding step*/
IF NOT EXISTS(SELECT * FROM Temp)
    DROP TABLE Temp /*Drop obsolete table*/

在SQL Server 2012中,可以使用SEQUENCES

更快地更新自动递增列
CREATE SEQUENCE Seq
    AS INT
    START WITH 1
    INCREMENT BY 1

CREATE TABLE Test2
(
ID INT DEFAULT NEXT VALUE FOR Seq NOT NULL PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test2(X)
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

UPDATE Test2 SET ID+=1

答案 2 :(得分:26)

通过SQL Server 2005管理器中的UI,更改列删除列的autonumber(identity)属性(通过右键单击选择表并选择“Design”)。

然后运行您的查询:

UPDATE table SET Id = Id + 1

然后将自动编号属性添加回列。

答案 3 :(得分:18)

首先,对此事项开启或关闭IDENTITY_INSERT的设置将不适用于您所需的内容(它用于插入新值,例如插入间隙)。

通过GUI执行操作只会创建一个临时表,将所有数据复制到没有标识字段的新表中,并重命名该表。

答案 4 :(得分:9)

这可以使用临时表来完成。

想法

  • 禁用约束(如果您的ID由外键引用)
  • 使用新ID
  • 创建临时表
  • 删除表格内容
  • 将复制的表格中的数据复制到原始表格
  • 启用预先禁用的约束

SQL查询

假设您的test表有两个额外的列(column2column3),并且有2个表的外键引用test,称为foreign_table1foreign_table2(因为现实生活中的问题从来都不简单)。

alter table test nocheck constraint all;
alter table foreign_table1 nocheck constraint all;
alter table foreign_table2 nocheck constraint all;
set identity_insert test on;

select id + 1 as id, column2, column3 into test_copy from test v;
delete from test;
insert into test(id, column2, column3)
select id, column2, column3 from test_copy

alter table test check constraint all;
alter table foreign_table1 check constraint all;
alter table foreign_table2 check constraint all;
set identity_insert test off;
drop table test_copy;

就是这样。

答案 5 :(得分:6)

DBCC CHECKIDENT('databasename.dbo.orders',RESEED,999) 您可以使用此命令更改任何标识列号,也可以从您想要的每个数字开始该字段编号。例如,在我的命令中,我要求从1000开始(999 + 1) 希望这就够了......祝你好运

答案 6 :(得分:4)

如果该列不是PK,您可以随时在表格中使用递增的数字创建一个新列,删除原始列,然后将新的列更改为旧的。

好奇为什么你可能需要这样做...大多数我曾经不得不使用Identity专栏来回填数字,我最后使用了DBCC CHECKIDENT(tablename,RESEED,newnextnumber)

祝你好运!

答案 7 :(得分:1)

身份修改可能会失败,具体取决于许多因素,主要是围绕链接到id列的对象/关系。似乎数据库设计在这里是问题,因为id应该很少,如果有变化(我确定你有你的理由,并且正在改变)。如果你真的需要不时更改id,我建议你创建一个新的虚拟id列,它不是你可以自己管理并从当前值生成的主键/自动编号。或者,如果您在允许身份插入时遇到问题,那么上面的Chrisotphers想法将是我的另一个建议。

祝你好运

PS它没有失败,因为它运行的顺序正在尝试将列表中的值更新为已存在于ID列表中的项目?抓住吸管,或许添加行数+ 1,然后如果可行则减去行数:-S

答案 8 :(得分:1)

如果您需要偶尔更改ID,最好不要使用标识列。过去,我们使用“计数器”表手动实现自动编号字段,该表跟踪每个表的下一个ID。 IIRC我们这样做是因为标识列导致SQL2000中的数据库损坏,但能够更改ID有时对测试很有用。

答案 9 :(得分:1)

您可以插入具有修改值的新行,然后删除旧行。以下示例更改ID与外键 PersonId

相同
SET IDENTITY_INSERT [PersonApiLogin] ON

INSERT INTO [PersonApiLogin](
       [Id]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess])
SELECT [PersonId]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess]
FROM [db304].[dbo].[PersonApiLogin]
GO

DELETE FROM [PersonApiLogin]
WHERE [PersonId] <> ID
GO
SET IDENTITY_INSERT [PersonApiLogin] OFF
GO

答案 10 :(得分:1)

首先保存所有ID并以编程方式将它们更改为您想要的值,然后将它们从数据库中删除,然后使用类似的东西再次插入它们:

use [Name.Database]
go
set identity_insert [Test] ON
insert into [dbo].[Test]
           ([Id])
     VALUES
           (2)
set identity_insert [Test] OFF

批量插入使用:

use [Name.Database]
go
set identity_insert [Test] ON
BULK INSERT [Test]
FROM 'C:\Users\Oscar\file.csv'
WITH (FIELDTERMINATOR = ';',
      ROWTERMINATOR = '\n',
      KEEPIDENTITY)
set identity_insert [Test] OFF

来自file.csv的示例数据:

2;
3;
4;
5;
6;

如果您未将identity_insert设置为关闭,则会收到以下错误:

  

无法在表'Test'中为identity列插入显式值   IDENTITY_INSERT设置为OFF。

答案 11 :(得分:0)

我看到一篇很好的文章在最后一刻帮助了我..我试图在一个有标识列的表中插入几行但是做错了而且必须删除。删除行后,我的标识列发生了变化。我试图找到一种方法来更新插入的列但是 - 没有运气。所以,在google上搜索时发现了一个链接..

  1. 删除了错误插入的列
  2. 使用身份开启/关闭强制插入(如下所述)
  3. http://beyondrelational.com/modules/2/blogs/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do-i-update-the-value-of-an.aspx

答案 12 :(得分:0)

非常好的问题,首先我们需要 on 特定表的IDENTITY_INSERT,之后运行插入查询(必须指定列名)。

注意:修改标识列后,请不要忘记关闭 IDENTITY_INSERT。如果您还没有完成,则无法编辑任何其他表的标识列。

SET IDENTITY_INSERT Emp_tb_gb_Menu ON
     INSERT Emp_tb_gb_Menu(MenuID) VALUES (68)
SET IDENTITY_INSERT Emp_tb_gb_Menu OFF

http://allinworld99.blogspot.com/2016/07/how-to-edit-identity-field-in-sql.html