我试着做这个查询

INSERT INTO dbo.tbl_A_archive
  SELECT *
  FROM SERVER0031.DB.dbo.tbl_A

但即使在我跑了之后

set identity_insert dbo.tbl_A_archive on

我得到这个错误消息

表'dbo中标识列的显式值。tbl_A_archive'只能在使用列列表且IDENTITY_INSERT为ON时指定。

tbl_A是一个行和宽都很大的表,也就是说它有很多列。我不想手动输入所有的列。我怎样才能让它工作呢?


当前回答

总结

SQL Server不允许您在标识列中插入显式值,除非您使用列列表。因此,你有以下选项:

制作一个列列表(手动或使用工具,见下文)

OR

将tbl_A_archive中的标识列设置为常规的非标识列:如果您的表是一个归档表,并且总是为标识列显式指定一个值,那么为什么还需要标识列呢?只需要使用常规int型就可以了。


方案一详细说明

而不是

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

你需要写

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table (field1, field2, ...)
  SELECT field1, field2, ...
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

用field1, field2,…包含表中所有列的名称。如果您想自动生成列列表,请查看Dave的答案或Andomar的答案。


方案二详细说明

不幸的是,仅仅将单位int列的“类型”更改为非单位int列是不可能的。基本上,你有以下几种选择:

如果存档表还不包含数据,则删除该列并添加一个不带标识的新列。

OR

使用SQL Server Management Studio将存档表中的标识列的标识规范/(是标识)属性设置为No。在幕后,这将创建一个脚本来重新创建表并复制现有数据,因此,要做到这一点,您还需要取消设置Tools/Options/Designers/ table和Database Designers/Prevent保存需要重新创建表的更改。

OR

使用此回答中描述的解决方法之一:从表中的列中删除标识

其他回答

此代码片段显示当标识主键列为ON时如何插入到表中。

SET IDENTITY_INSERT [dbo].[Roles] ON
GO
insert into Roles (Id,Name) values(1,'Admin')
GO
insert into Roles (Id,Name) values(2,'User')
GO
SET IDENTITY_INSERT [dbo].[Roles] OFF
GO
SET IDENTITY_INSERT tableA ON

你必须为INSERT语句创建一个列列表:

INSERT Into tableA ([id], [c2], [c3], [c4], [c5] ) 
SELECT [id], [c2], [c3], [c4], [c5] FROM tableB

不像“INSERT Into tableA SELECT ........”

SET IDENTITY_INSERT tableA OFF

如果您正在使用SQL Server Management Studio,您不必自己键入列列表-只需在对象资源管理器中右键单击表,并选择脚本表作为-> SELECT到->新建查询编辑器窗口。

如果你不是,那么类似的查询应该有助于作为一个起点:

SELECT SUBSTRING(
    (SELECT ', ' + QUOTENAME(COLUMN_NAME)
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'tbl_A'
        ORDER BY ORDINAL_POSITION
        FOR XML path('')),
    3,
    200000);

总结

SQL Server不允许您在标识列中插入显式值,除非您使用列列表。因此,你有以下选项:

制作一个列列表(手动或使用工具,见下文)

OR

将tbl_A_archive中的标识列设置为常规的非标识列:如果您的表是一个归档表,并且总是为标识列显式指定一个值,那么为什么还需要标识列呢?只需要使用常规int型就可以了。


方案一详细说明

而不是

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

你需要写

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table (field1, field2, ...)
  SELECT field1, field2, ...
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

用field1, field2,…包含表中所有列的名称。如果您想自动生成列列表,请查看Dave的答案或Andomar的答案。


方案二详细说明

不幸的是,仅仅将单位int列的“类型”更改为非单位int列是不可能的。基本上,你有以下几种选择:

如果存档表还不包含数据,则删除该列并添加一个不带标识的新列。

OR

使用SQL Server Management Studio将存档表中的标识列的标识规范/(是标识)属性设置为No。在幕后,这将创建一个脚本来重新创建表并复制现有数据,因此,要做到这一点,您还需要取消设置Tools/Options/Designers/ table和Database Designers/Prevent保存需要重新创建表的更改。

OR

使用此回答中描述的解决方法之一:从表中的列中删除标识

两者都可以工作,但如果使用#1仍然会出错,那么就使用#2

1)

SET IDENTITY_INSERT customers ON
GO
insert into dbo.tbl_A_archive(id, ...)
SELECT Id, ...
FROM SERVER0031.DB.dbo.tbl_A

2)

SET IDENTITY_INSERT customers ON
GO
insert into dbo.tbl_A_archive(id, ...)
VALUES(@Id,....)