160

我有一个Test带有列的表的 MS SQL 2005 数据库IDID是一个标识列。

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

现在我想像这样更改此表中的每个 ID:

ID = ID + 1

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

无法更新标识列“ID”。

我试过这个:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

但这并不能解决问题。

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

4

13 回答 13

226

你需要

set identity_insert YourTable ON

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

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

set identity_insert YourTable OFF
于 2009-07-27T13:15:27.147 回答
39

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
于 2013-06-22T10:16:44.463 回答
26

通过 SQL Server 2005 管理器中的 UI,更改列删除列的自动编号(身份)属性(通过右键单击选择表并选择“设计”)。

然后运行您的查询:

UPDATE table SET Id = Id + 1

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

于 2009-04-15T12:48:01.927 回答
18

首先,IDENTITY_INSERT 的设置为 on 或 off 将无法满足您的要求(它用于插入新值,例如堵塞间隙)。

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

于 2009-04-15T13:32:50.743 回答
9

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

这个想法

  • 禁用约束(如果您的 id 被外键引用)
  • 用新的 id 创建一个临时表
  • 删除表格内容
  • 将复制表中的数据复制回原始表
  • 启用先前禁用的约束

SQL 查询

假设您的test表有两个额外的列 ( column2and column3),并且有 2 个表的外键引用test称为foreign_table1and foreign_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;

就是这样。

于 2012-08-30T15:09:19.097 回答
6

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

于 2012-04-11T20:18:55.117 回答
4

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

好奇为什么你可能需要这样做......我曾经用身份列做的最重要的是回填数字,我最终使用 DBCC CHECKIDENT (tablename,RESEED,newnextnumber)

祝你好运!

于 2009-04-15T13:01:03.333 回答
1

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

祝你好运

PS它没有失败,因为它运行的顺序是试图将列表中的值更新为id列表中已经存在的项目?抓住稻草,也许加上行数+1,然后如果可行,减去行数:-S

于 2009-04-15T13:10:56.087 回答
1

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

于 2009-07-27T10:18:12.513 回答
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
于 2015-02-05T21:01:02.930 回答
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为关闭,您将收到以下错误:

当 IDENTITY_INSERT 设置为 OFF 时,无法在表“Test”中插入标识列的显式值。

于 2016-08-08T13:34:46.127 回答
0

我看到了一篇很好的文章,它在最后一刻帮助了我。我试图在一个有标识列的表中插入几行,但做错了,不得不删除回来。一旦我删除了这些行,我的身份列就会改变。我试图找到一种方法来更新插入的列,但是 - 没有运气。所以,在谷歌搜索时发现了一个链接..

  1. 删除了错误插入的列
  2. 使用身份打开/关闭强制插入(如下所述)

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

于 2012-09-17T23:41:06.977 回答
0

非常好的问题,首先我们需要对特定表进行 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

于 2016-07-27T10:01:32.153 回答