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


187

Я намагаюся зробити цей запит

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.

tbl_Aце величезна таблиця в рядках і ширині, тобто вона має багато стовпців. Я не хочу вводити всі стовпці вручну. Як я можу змусити це працювати?


Я вже встановив пов'язаний сервер, до речі!
jhowe

4
У мене також є ця проблема, за винятком "вставки в X select * 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 для встановлення параметра Identity Specification/ (Is Identity)властивості стовпця особи у вашій таблиці архівів No. За лаштунками це створить сценарій для повторного створення таблиці та копіювання наявних даних, тож для цього вам також знадобиться скасувати Tools// Options/ Designers/ Table and Database Designers/ Prevent saving changes that require table re-creation.

АБО


1
До вашого нижнього рішення: Якщо у стовпці є "ІДЕНТИЧНІСТЬ (1, 1)" або щось подібне, його потрібно буде також видалити тимчасово.
Олександр Хоменко

1
@AleksandrKhomenko: Так, саме це я мав на увазі під «перетворити [it] у звичайний ( неідентифікаційний ) колонку int» .
Хайнці

1
Вибачте за непорозуміння. Я мав на увазі, що він також повинен буде видалити властивість автоматичного збільшення . У випадку з SQL-сервером він називає "ІДЕНТИЧНІСТЬ (1, 1)" - ваша відповідь абсолютно правильна. Але у MySQL та Oracle є й інші команди для цього (і це стає неочевидним, дивіться на w3schools.com/sql/sql_autoincrement.asp )
Олександр Хоменко

2
Цього бракує докладно. Я розумію, що це може бути грішним для одних, але для інших це нісенітниця
DJ.

1
@ D.J .: Я додав деякі деталі.
Хайнзі

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
Я отримав цю помилку, коли стовпці у пункті вибору не збігалися з цільовою таблицею. Переконавшись у цьому, вставка працювала для мене
Хосе

39

Якщо ви використовуєте SQL Server Management Studio, вам не доведеться самостійно вводити список стовпців - просто клацніть правою кнопкою миші таблицю в Провіднику об’єктів і виберіть Таблиця сценаріїв як -> SELECT to -> New Query Editor Window .

Якщо ви цього не зробите, то запит, подібний до цього, повинен допомогти початковою точкою:

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-запиті. Ти врятував мені день. Дуже дякую!
Pawel Cioch

1
Дякую! Я зробив це за допомогою gist.github.com/timabell/0ddd6a69565593f907c7
Тім

Ого. я відчайдушно шукав це, щоб будувати свій запит динамічно. Здивовано, побачивши це тут. Дякую, друже.
Ясін Білір

24

Погодьтеся з відповіддю Хайнзі. Для першого варіанту, ось запит, який генерує розділений комою список стовпців у таблиці:

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

Для великих столів це може заощадити багато набору тексту :)


@ Дякую, дуже корисно. :)
Chirag Thakar

Іноді просто потрібно прагматичне рішення. Дякую!
Tobias

15

Якщо таблиця "архіву" має бути точною копією головної таблиці, тоді я просто запропонував би вам видалити факт, що ідентифікатор - це стовпець ідентифікації. Таким чином він дозволить вам вставити їх.

Крім того, ви можете дозволити і заборонити вставки ідентифікаційних даних для таблиці із наступним твердженням

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
Це насправді не так, якщо ОП вставляє кілька записів. Ви ігноруєте "tbl_A - це величезна таблиця в рядках і ширині, тобто вона має багато стовпців. Я не хочу вводити всі стовпці вручну".
Гері

4

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

1)

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

2) Це, мабуть, найпростіший підхід до створення стовпців, якщо у вас є SSMS SQL Server.

1) Перейдіть до таблиці в Object Explorer і натисніть + ліворуч від імені таблиці або двічі клацніть ім'я таблиці, щоб відкрити підсписок.

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, оскільки перемикаюся між екземплярами.

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

Я думаю, що ця помилка виникає через невідповідність кількості колонок у визначенні таблиці та кількості стовпців у запиті вставки. Також довжина стовпця опущена із введеним значенням. Тому просто перегляньте визначення таблиці, щоб вирішити цю проблему


Працювало для мене: я забув додати стовпчик до таблиці з дизайну, добре перевірити це для початку, перш ніж спробувати інші відповіді.
Гамбоа
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.