Явное значение для столбца идентификаторов в таблице можно указывать только в том случае, если используется список столбцов, а IDENTITY_INSERT установлен на ON SQL Server.


188

Я пытаюсь сделать этот запрос

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огромная таблица в строках и ширине, то есть имеет много столбцов. Я не хочу печатать все столбцы вручную. Как я могу заставить это работать?


Кстати, я уже настроил связанный сервер!
jhowe

4
У меня также есть эта проблема, за исключением того, что «вставить в X выберите * Y» не было проблемой, пока я не изменил схему таблицы
FistOfFury

Ответы:


81

Резюме

SQL Server не позволит вам вставить явное значение в столбец идентификаторов, если вы не используете список столбцов. Таким образом, у вас есть следующие варианты:

  1. Составьте список столбцов (вручную или с помощью инструментов, см. Ниже)

ИЛИ

  1. сделайте столбец идентификаторов в tbl_A_archiveобычном столбце без идентификаторов : если ваша таблица является архивной таблицей, и вы всегда указываете явное значение для столбца идентификаторов, зачем вам вообще нужен столбец идентификаторов? Просто используйте обычный int вместо.

Подробная информация о решении 1

Вместо того

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, ...содержанием имен всех столбцов в ваших таблицах. Если вы хотите автоматически сгенерировать этот список столбцов, взгляните на ответ Дейва или ответ Андомара .


Подробная информация о решении 2

К сожалению, невозможно просто «изменить тип» столбца типа int на столбец типа int без идентификатора. По сути, у вас есть следующие варианты:

  • Если таблица архива еще не содержит данных, отбросьте столбец и добавьте новый без идентификатора.

ИЛИ

  • Используйте SQL Server Management Studio, чтобы установить для свойства Identity Specification/ (Is Identity)столбца идентификаторов в таблице архива значение No. За кулисами это создаст скрипт для воссоздания таблицы и копирования существующих данных, поэтому для этого вам также нужно будет удалить Tools/ Options/ Designers/ Table and Database Designers/ Prevent saving changes that require table re-creation.

ИЛИ


1
К вашему нижнему решению: если в столбце указано «IDENTITY (1, 1)» или что-то в этом роде, ему также потребуется удалить его временно.
Александр Хоменко

1
@AleksandrKhomenko: Да, именно это я и имел в виду под «сделать [это] обычным ( не идентифицирующим ) int столбцом» .
Хайнци

1
Извините за путаницу. На самом деле я имел в виду, что ему тоже нужно будет удалить свойство автоинкремента . В случае SQL-сервера он называет «IDENTITY (1, 1)» - ваш ответ абсолютно верен. Но у MySQL и Oracle есть другие команды для этого (и это становится неочевидным, пожалуйста, посмотрите на w3schools.com/sql/sql_autoincrement.asp )
Александр Хоменко

2
Это не хватает в деталях. Я понимаю, что для одних это может быть бессмысленно, а для других
.

1
@DJ .: Я добавил некоторые детали.
Хайнци

332
SET IDENTITY_INSERT tableA ON

Вы должны составить список столбцов для вашего оператора INSERT:

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

не похоже на "Вставить в таблицу A SELECT ........"

SET IDENTITY_INSERT tableA OFF

17
+1 ... Вам нужны только явные столбцы в предложении SELECT запроса. Вы можете оставить звездочку в предложении INSERT запроса
MacGyver

8
... если у цели нет столбца идентификаторов, а у исходной таблицы нет столбца идентификаторов
MacGyver

1
этот ответ немного более ясен, чем Хайнци, потому что в нем упоминается SET IDENTITY_INSERT
Марти

4
+1 Работает как шарм! Однако «Вы можете оставить звездочку в предложении INSERT запроса» здесь не сработает.
Шай Алон

1
Я получил эту ошибку, когда столбцы в предложении select не совпадали с таблицей назначения. Убедившись в этом, вставка сработала для меня
Хосе

39

Если вы используете SQL Server Management Studio, вам не нужно вводить список столбцов самостоятельно - просто щелкните правой кнопкой мыши таблицу в обозревателе объектов и выберите Таблица сценариев как -> ВЫБРАТЬ - -> Окно нового редактора запросов .

Если нет, то запрос, подобный этому, должен помочь в качестве отправной точки:

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

2
Это можно выбрать в переменную и использовать в динамическом запросе SQL. Ты спас мой день. Большое спасибо!
Павел Cioch

1
Спасибо! Я сделал это с этим gist.github.com/timabell/0ddd6a69565593f907c7
Тим Абелл

Вот это да. я отчаянно искал это, чтобы построить мой запрос динамически. Удивлен, увидев это здесь. Спасибо друг.
Ясин Билир

24

Согласитесь с ответом Хайнци. Для первого второго варианта, вот запрос, который генерирует разделенный запятыми список столбцов в таблице:

select name + ', ' as [text()] 
from sys.columns 
where object_id = object_id('YourTable') 
for xml path('')

Для больших таблиц это может сэкономить много печатной работы :)


@ Спасибо, действительно полезно. :)
Чираг Тхакар

Иногда вам просто нужно прагматичное решение. Спасибо!
Тобиас Фейл

15

Если «архивная» таблица должна быть точной копией вашей основной таблицы, я бы просто предложил вам удалить тот факт, что id является столбцом идентификаторов. Таким образом, это позволит вам вставить их.

В качестве альтернативы вы можете разрешить и запретить вставку идентификаторов для таблицы с помощью следующего оператора

SET IDENTITY_INSERT tbl_A_archive ON
--Your inserts here
SET IDENTITY_INSERT tbl_A_archive OFF

Наконец, если вам нужно, чтобы столбец идентификаторов работал как есть, вы всегда можете просто запустить сохраненный процесс.

sp_columns tbl_A_archive 

Это вернет вам все столбцы из таблицы, которые вы можете затем вырезать и вставить в свой запрос. (Это почти всегда лучше, чем использование *)


11

Для оператора SQL вы также должны указать список столбцов. Например,

INSERT INTO tbl (idcol1,col2) VALUES ( value1,value2)

вместо того

INSERT INTO tbl VALUES ( value1,value2)

2
Это не относится к заявлению ФП. VALUES не требуется, если за INSERT INTO следует оператор SELECT. Пожалуйста, измените или удалите свой ответ.
Гэри

4

Оба будут работать, но если вы все равно получите ошибку, используя # 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,....)

4
Это действительно не тот путь, если OP вставляет несколько записей. Вы игнорируете: «tbl_A - огромная таблица в строках и ширине, то есть в ней много столбцов. Я не хочу печатать все столбцы вручную».
Гэри

4

Чтобы заполнить все имена столбцов в списке, разделенном запятыми, для оператора Select для решений, упомянутых для этого вопроса, я использую следующие параметры, так как они немного менее многословны, чем большинство ответов здесь. Хотя большинство ответов здесь все же вполне приемлемо.

1)

SELECT column_name + ',' 
FROM   information_schema.columns 
WHERE  table_name = 'YourTable'

2) Это, вероятно, самый простой подход к созданию столбцов, если у вас есть SQL Server SSMS.

1) Перейдите к таблице в обозревателе объектов и нажмите + слева от имени таблицы или дважды щелкните имя таблицы, чтобы открыть подсписок.

2) Перетащите подпапку столбца в основную область запроса, и он автоматически вставит весь список столбцов.


3

Вам необходимо указать имя столбца, который вы хотите вставить, если есть столбец Identity. Таким образом, команда будет выглядеть так:

SET IDENTITY_INSERT DuplicateTable ON

INSERT Into DuplicateTable ([IdentityColumn], [Column2], [Column3], [Column4] ) 
SELECT [IdentityColumn], [Column2], [Column3], [Column4] FROM MainTable

SET IDENTITY_INSERT DuplicateTable OFF

Если в вашей таблице много столбцов, используйте эту команду для получения имени этих столбцов.

SELECT column_name + ','
FROM   information_schema.columns 
WHERE  table_name = 'TableName'
for xml path('')

(после удаления последней запятой (',')) Просто скопируйте имя последнего столбца.


3

Это должно работать. Я просто столкнулся с вашей проблемой:

SET IDENTITY_INSERT dbo.tbl_A_archive ON;
INSERT INTO     dbo.tbl_A_archive (IdColumn,OtherColumn1,OtherColumn2,...)
SELECT  *
FROM        SERVER0031.DB.dbo.tbl_A;
SET IDENTITY_INSERT dbo.tbl_A_archive OFF;

К сожалению, кажется, вам нужен список столбцов, включая столбец идентификаторов, чтобы вставить записи, в которых указан идентификатор. Тем не менее , вы не должны перечислять столбцы в SELECT. Как предположил @Dave Cluderay, это приведет к тому, что вы сможете скопировать и вставить отформатированный список (если меньше 200000 символов).

Я добавил ИСПОЛЬЗОВАНИЕ, так как я переключаюсь между экземплярами.

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

3
SET IDENTITY_INSERT tableA ON

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

Не так

INSERT INTO tableA
SELECT * FROM tableB

SET IDENTITY_INSERT tableA OFF

2

Этот фрагмент кода показывает, как вставить в таблицу, когда столбец идентификатора первичного ключа включен.

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

1

Если вы хотите вставить свои значения из одной таблицы в другую через хранимую процедуру. Я использовал это и это , последнее, что почти как ответ Андомара.

CREATE procedure [dbo].[RealTableMergeFromTemp]
    with execute as owner
AS
BEGIN
BEGIN TRANSACTION RealTableDataMerge
SET XACT_ABORT ON

    DECLARE @columnNameList nvarchar(MAX) =
     STUFF((select ',' + a.name
      from sys.all_columns a
      join sys.tables t on a.object_id = t.object_id 
       where t.object_id = object_id('[dbo].[RealTable]') 
    order by a.column_id
    for xml path ('')
    ),1,1,'')

    DECLARE @SQLCMD nvarchar(MAX) =N'INSERT INTO [dbo].[RealTable] (' + @columnNameList + N') SELECT * FROM [#Temp]'

    SET IDENTITY_INSERT [dbo].[RealTable] ON;
    exec(@sqlcmd)
    SET IDENTITY_INSERT [dbo].[RealTable] OFF

COMMIT TRANSACTION RealTableDataMerge
END

GO

0

Существует один или несколько столбцов, которые имеют свойство автоинкремента, или значение этого атрибута будет рассчитываться как ограничение. Вы пытаетесь изменить этот столбец.

Есть два способа решить это: 1) Явно упомянуть другие столбцы и установить только их значения, и значение PrimaryKey или значение автоинкремента будет установлено автоматически.

2) Вы можете включить INDENTITY_INSERT, затем выполнить запрос вставки и, наконец, отключить IDENTITY_INSERT.

Предложение: выполните первый шаг, потому что это более подходящий и эффективный подход.

Для получения дополнительной информации прочитайте эту статью на SQL-помощник .


0

Убедитесь, что имена столбцов, типы данных и порядок в таблице, из которой вы выбираете записи, в точности совпадают с таблицей назначения. Единственная разница должна заключаться в том, что таблица назначения имеет столбец идентификатора в качестве первого столбца, которого нет в исходной таблице.

Я столкнулся с подобной проблемой, когда выполнял «INSERT INTO table_Dest SELECT * FROM table_source_linked_server_excel». Таблицы имели 115 столбцов.

У меня было две такие таблицы, где я загружал данные из Excel (как связанный сервер) в таблицы в базе данных. В таблицах базы данных я добавил столбец идентификаторов «id», которого не было в исходном Excel. Для одной таблицы запрос выполнялся успешно, а в другой я получил сообщение об ошибке «Явное значение для столбца идентификаторов в таблице можно указывать только в том случае, если используется список столбцов, а IDENTITY_INSERT включен ON SQL Server». Это было загадочно, так как сценарий был одинаковым для обоих запросов. Поэтому я исследовал это и обнаружил, что в запросе, где я получаю сообщение об ошибке с INSERT INTO .. ​​SELECT *:

  1. Некоторые имена столбцов в исходной таблице были изменены, хотя значения были правильными
  2. Были некоторые дополнительные столбцы помимо фактических столбцов данных, которые были выбраны с помощью SELECT *. Я обнаружил это с помощью опции «Таблица сценариев как> Выбрать для> нового окна запроса» в исходной таблице Excel (в разделе связанных серверов). Сразу после последнего столбца в Excel был один скрытый столбец, хотя в нем не было никаких данных. Я удалил этот столбец в исходной таблице Excel и сохранил его.

После двух вышеуказанных изменений запрос INSERT INTO ... SELECT * был успешно выполнен. Столбец идентификаторов в таблице назначения генерирует значения идентификаторов для каждой вставленной строки, как и ожидалось.

Таким образом, даже если таблица назначения может иметь столбец идентификаторов, которого нет в исходной таблице, INSERT INTO .. ​​SELECT * будет успешно выполнен, если имена, типы данных и порядок столбцов в источнике и месте назначения точно совпадают.

Надеюсь, это кому-нибудь поможет.


-1

Я думаю, что эта ошибка происходит из-за несоответствия с количеством столбцов в определении таблицы и количеством столбцов в запросе вставки. Также длина столбца опускается с введенным значением. Так что просто просмотрите определение таблицы, чтобы решить эту проблему


Сработало для меня: я забыл добавить столбец в таблицу из дизайна, хорошая вещь, чтобы проверить это, прежде чем пытаться найти другие ответы.
Exel Gamboa
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.