Nilai eksplisit untuk kolom identitas dalam tabel hanya dapat ditentukan ketika daftar kolom digunakan dan IDENTITY_INSERT adalah ON SQL Server

187

Saya mencoba melakukan kueri ini

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

tetapi bahkan setelah saya berlari

set identity_insert dbo.tbl_A_archive on

Saya menerima pesan kesalahan ini

Nilai eksplisit untuk kolom identitas pada tabel 'dbo.tbl_A_archive' hanya dapat ditentukan ketika daftar kolom digunakan dan IDENTITY_INSERT adalah ON.

tbl_Aadalah tabel besar dalam baris dan lebar, yaitu memiliki BANYAK kolom. Saya tidak ingin harus mengetik semua kolom secara manual. Bagaimana saya bisa membuatnya bekerja?

jhowe
sumber
saya sudah menyiapkan server yang terhubung dengan cara!
jhowe
4
Saya mengalami masalah ini juga, kecuali "masukkan ke X pilih * Y" tidak masalah sampai saya mengubah skema tabel
FistOfFury

Jawaban:

81

Ringkasan

SQL Server tidak akan membiarkan Anda memasukkan nilai eksplisit dalam kolom identitas kecuali Anda menggunakan daftar kolom. Dengan demikian, Anda memiliki opsi berikut:

  1. Buat daftar kolom (baik secara manual atau menggunakan alat, lihat di bawah)

ATAU

  1. buat kolom identitas dalam kolom tbl_A_archivebiasa, non-identitas : Jika tabel Anda adalah tabel arsip dan Anda selalu menentukan nilai eksplisit untuk kolom identitas, mengapa Anda membutuhkan kolom identitas? Cukup gunakan int biasa saja.

Detail tentang Solusi 1

Dari pada

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

kamu perlu menulis

SET IDENTITY_INSERT archive_table ON;

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

SET IDENTITY_INSERT archive_table OFF;

dengan field1, field2, ...berisi nama-nama semua kolom di tabel Anda. Jika Anda ingin membuat-otomatis daftar kolom itu, lihat jawaban Dave atau jawaban Andomar .


Detail tentang Solusi 2

Sayangnya, tidak mungkin untuk hanya "mengubah jenis" kolom int identitas ke kolom int identitas. Pada dasarnya, Anda memiliki opsi berikut:

  • Jika tabel arsip belum berisi data, jatuhkan kolom dan tambahkan yang baru tanpa identitas.

ATAU

  • Gunakan SQL Server Management Studio untuk mengatur Identity Specification/ (Is Identity)properti kolom identitas di tabel arsip Anda No. Di belakang layar, ini akan membuat skrip untuk membuat ulang tabel dan menyalin data yang ada, jadi, untuk melakukan itu, Anda juga harus menghapus Tools/ Options/ Designers/ Table and Database Designers/ Prevent saving changes that require table re-creation.

ATAU

Heinzi
sumber
1
Untuk solusi bawah Anda: Jika kolom memiliki "IDENTITY (1, 1)" atau sesuatu seperti ini, ia perlu menghapusnya sementara.
Aleksandr Khomenko
1
@AleksandrKhomenko: Ya, itulah yang saya maksud dengan "menjadikannya kolom int ( non-identitas ) reguler " .
Heinzi
1
Maaf bila membingungkan. Sebenarnya saya maksudkan bahwa dia juga perlu menghapus properti kenaikan-otomatis . Dalam kasus SQL-Server disebut "IDENTITAS (1, 1)" - jawaban Anda benar sekali. Tetapi MySQL dan Oracle memiliki perintah lain untuk itu (dan itu menjadi tidak jelas, silakan lihat w3schools.com/sql/sql_autoincrement.asp )
Aleksandr Khomenko
2
Ini kurang detail. Saya mengerti ini mungkin menghafal beberapa orang tetapi tidak masuk akal bagi yang lain
DJ.
1
@ DJ: Saya telah menambahkan beberapa detail.
Heinzi
332
SET IDENTITY_INSERT tableA ON

Anda harus membuat daftar kolom untuk pernyataan INSERT Anda:

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

tidak suka "INSERT Into tableA SELECT ........"

SET IDENTITY_INSERT tableA OFF
Ehsan
sumber
17
+1 ... Anda hanya perlu kolom eksplisit di klausa SELECT dari kueri. Anda dapat menyimpan tanda bintang di klausa INSERT dari kueri
MacGyver
8
... kecuali target memiliki kolom identitas, dan tabel sumber tidak memiliki kolom identitas
MacGyver
1
jawaban ini sedikit lebih jelas daripada Heinzi karena menyebutkan SET IDENTITY_INSERT
Marty
4
+1 Bekerja seperti pesona! Namun, "Anda dapat menyimpan tanda bintang di klausa INSERT permintaan" tidak akan berfungsi di sini.
Shai Alon
1
Saya mendapatkan kesalahan ini ketika kolom dalam klausa pilih tidak cocok dengan tabel tujuan. Memastikan hal ini, sisipan berhasil untuk saya
Jose
39

Jika Anda menggunakan SQL Server Management Studio, Anda tidak perlu mengetik sendiri daftar kolom - cukup klik kanan tabel di Object Explorer dan pilih Script Table sebagai -> SELECT to -> New Query Editor Window .

Jika tidak, maka kueri yang mirip dengan ini akan membantu sebagai titik awal:

SELECT SUBSTRING(
    (SELECT ', ' + QUOTENAME(COLUMN_NAME)
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'tbl_A'
        ORDER BY ORDINAL_POSITION
        FOR XML path('')),
    3,
    200000);
Dave Cluderay
sumber
2
Ini bisa dipilih menjadi variabel dan digunakan dalam query SQL dinamis. Kamu menyelamatkan hariku. Terima kasih banyak!
Pawel Cioch
1
Terima kasih! Saya membuatnya dengan itu gist.github.com/timabell/0ddd6a69565593f907c7
Tim Abell
Wow. Saya putus asa mencari ini untuk membangun permintaan saya secara dinamis. Terkejut melihat ini di sini. Terima kasih sobat.
Yasin Bilir
24

Setuju dengan jawaban Heinzi. Untuk opsi kedua pertama, inilah kueri yang menghasilkan daftar kolom yang dipisahkan koma dalam tabel:

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

Untuk tabel besar, ini bisa menghemat banyak pekerjaan mengetik :)

Andomar
sumber
@ Terima kasih, sangat membantu. :)
Chirag Thakar
Terkadang Anda hanya membutuhkan solusi pragmatis. Terima kasih!
Tobias Feil
15

Jika tabel "arsip" dimaksudkan untuk menjadi salinan tepat dari tabel utama Anda maka saya hanya menyarankan agar Anda menghapus fakta bahwa id adalah kolom identitas. Dengan begitu itu akan membiarkan Anda memasukkannya.

Atau Anda dapat mengizinkan dan melarang sisipan identitas untuk tabel dengan pernyataan berikut

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

Akhirnya, jika Anda membutuhkan kolom identitas untuk berfungsi sebagaimana mestinya maka Anda selalu dapat menjalankan proc yang disimpan.

sp_columns tbl_A_archive 

Ini akan mengembalikan Anda semua kolom dari tabel yang kemudian dapat Anda potong dan tempel ke kueri Anda. (Ini hampir SELALU lebih baik daripada menggunakan *)

Robin Day
sumber
11

Untuk pernyataan SQL, Anda juga harus menentukan daftar kolom. Untuk misalnya.

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

dari pada

INSERT INTO tbl VALUES ( value1,value2)
Mohsin Mahmood
sumber
2
Ini tidak berlaku untuk pernyataan OP. VALUES tidak diperlukan jika INSERT INTO diikuti oleh pernyataan SELECT. Harap revisi atau hapus jawaban Anda.
Gary
4

Keduanya akan berfungsi, tetapi jika Anda masih mendapatkan kesalahan dengan menggunakan # 1 maka pergi untuk # 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,....)
Chirag Thakar
sumber
4
Ini benar-benar bukan cara untuk pergi jika OP memasukkan banyak catatan. Anda mengabaikan "tbl_A adalah tabel besar dalam baris dan lebar, artinya memiliki BANYAK kolom. Saya tidak mau harus mengetikkan semua kolom secara manual."
Gary
4

Untuk mengisi semua nama kolom ke dalam daftar terbatas koma untuk pernyataan Select untuk solusi yang disebutkan untuk pertanyaan ini, saya menggunakan opsi berikut karena mereka sedikit kurang bertele-tele daripada kebanyakan respons di sini. Meskipun demikian, sebagian besar tanggapan di sini masih dapat diterima dengan sempurna.

1)

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

2) Ini mungkin pendekatan paling sederhana untuk membuat kolom, jika Anda memiliki SQL Server SSMS.

1) Pergi ke tabel di Object Explorer dan klik pada + di sebelah kiri nama tabel atau klik dua kali nama tabel untuk membuka sub daftar.

2) Seret subfolder kolom ke area permintaan utama dan itu akan secara otomatis menempelkan seluruh daftar kolom untuk Anda.

Ryan
sumber
3

Anda harus menentukan nama kolom yang ingin Anda masukkan jika ada kolom Identitas. Jadi perintahnya akan seperti ini di bawah ini:

SET IDENTITY_INSERT DuplicateTable ON

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

SET IDENTITY_INSERT DuplicateTable OFF

Jika tabel Anda memiliki banyak kolom maka dapatkan nama kolom tersebut dengan menggunakan perintah ini.

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

(setelah menghapus koma terakhir (',')) Cukup salin nama kolom lalu.

Rousonur Jaman
sumber
3

Ini seharusnya bekerja. Saya baru saja mengalami masalah Anda:

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;

Sayangnya sepertinya Anda memang perlu daftar kolom termasuk kolom identitas untuk menyisipkan catatan yang menentukan Identitas. Namun , Anda tidak HARUS mendaftar kolom di SELECT. Seperti yang disarankan @Dave Cluderay, ini akan menghasilkan daftar yang diformat untuk Anda salin dan tempel (jika kurang dari 200000 karakter).

Saya menambahkan USE karena saya beralih antar instance.

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);
Gary
sumber
3
SET IDENTITY_INSERT tableA ON

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

Tidak seperti ini

INSERT INTO tableA
SELECT * FROM tableB

SET IDENTITY_INSERT tableA OFF
Kelinci
sumber
2

Cuplikan kode ini menunjukkan cara memasukkan ke dalam tabel saat kolom Kunci Utama identitas AKTIF.

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
AminGolmahalle
sumber
1

Karena jika Anda ingin memasukkan nilai-nilai Anda dari satu tabel ke yang lain melalui prosedur tersimpan. Saya menggunakan ini dan ini , yang terakhir yang hampir seperti jawaban Andomar.

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
Rubenisme
sumber
0

Ada satu atau lebih kolom yang memiliki properti kenaikan-otomatis atau nilai atribut itu akan dihitung sebagai kendala. Anda mencoba mengubah kolom itu.

Ada dua cara untuk menyelesaikannya 1) Sebutkan kolom lain secara eksplisit dan tetapkan hanya nilainya dan PrimaryKey atau nilai kolom kenaikan otomatis akan diatur secara otomatis.

2) Anda dapat mengaktifkan INDENTITY_INSERT kemudian menjalankan permintaan memasukkan Anda akhirnya mematikan IDENTITY_INSERT.

Saran: Ikuti langkah pertama karena ini merupakan pendekatan yang lebih cocok dan efisien.

Untuk informasi lebih lanjut, baca artikel ini di SQL-helper .

Shanu Dey
sumber
0

Pastikan bahwa nama kolom, tipe data, dan urutan dalam tabel dari mana Anda memilih catatan sama persis dengan tabel tujuan. Hanya perbedaan yang seharusnya tabel tujuan memiliki kolom identitas sebagai kolom pertama, yang tidak ada di tabel sumber.

Saya menghadapi masalah serupa ketika saya menjalankan "INSERT INTO table_Dest SELECT * FROM table_source_linked_server_excel". Tabel memiliki 115 kolom.

Saya punya dua tabel di mana saya memuat data dari Excel (Sebagai server yang ditautkan) ke dalam tabel dalam database. Dalam tabel database, saya telah menambahkan kolom identitas yang disebut 'id' yang tidak ada di sumber Excel. Untuk satu tabel kueri berjalan dengan sukses dan di lain saya mendapat kesalahan "Nilai eksplisit untuk kolom identitas dalam tabel hanya dapat ditentukan ketika daftar kolom digunakan dan IDENTITY_INSERT adalah ON SQL Server". Ini membingungkan karena skenario persis sama untuk kedua pertanyaan. Jadi saya menyelidiki ini dan apa yang saya temukan adalah bahwa dalam kueri di mana saya mendapatkan kesalahan dengan INSERT INTO .. ​​SELECT *:

  1. Beberapa nama kolom dalam tabel sumber diubah, meskipun nilainya benar
  2. Ada beberapa kolom tambahan di luar kolom data aktual yang dipilih oleh SELECT *. Saya menemukan ini dengan menggunakan opsi "Tabel skrip sebagai> Pilih ke> jendela kueri baru" pada tabel Excel sumber (di bawah server tertaut). Ada satu kolom tersembunyi tepat setelah kolom terakhir di Excel, meskipun tidak memiliki data. Saya menghapus kolom itu di tabel Excel sumber dan menyimpannya.

Setelah melakukan dua perubahan di atas, kueri untuk INSERT INTO ... SELECT * berhasil dijalankan. Kolom identitas di tabel tujuan menghasilkan nilai identitas untuk setiap baris yang dimasukkan seperti yang diharapkan.

Jadi, meskipun tabel tujuan mungkin memiliki kolom identitas yang tidak ada di tabel sumber, INSERT INTO .. ​​SELECT * akan berjalan dengan sukses jika nama, tipe data, dan urutan kolom dalam sumber dan tujuan sama persis.

Semoga ini bisa membantu seseorang.

Uttam
sumber
-1

Saya pikir kesalahan ini terjadi karena ketidakcocokan dengan jumlah kolom dalam definisi tabel dan jumlah kolom dalam permintaan memasukkan. Panjang kolom juga dihilangkan dengan nilai yang dimasukkan. Jadi cukup tinjau definisi tabel untuk menyelesaikan masalah ini

Pembuat kode
sumber
Bekerja untuk saya: Saya lupa menambahkan kolom ke tabel dari desain, hal yang baik untuk memeriksa ini terlebih dahulu sebelum mencoba jawaban lain.
Exel Gamboa