Tablodaki kimlik sütunu için açık bir değer yalnızca bir sütun listesi kullanıldığında ve IDENTITY_INSERT AÇIK SQL Server olduğunda belirtilebilir


188

Bu sorguyu yapmaya çalışıyorum

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

ama koştuktan sonra bile

set identity_insert dbo.tbl_A_archive on

Bu hata mesajını alıyorum

'Dbo.tbl_A_archive' tablosundaki kimlik sütunu için açık bir değer yalnızca bir sütun listesi kullanıldığında ve IDENTITY_INSERT AÇIK olduğunda belirlenebilir.

tbl_Asatır ve genişlikte büyük bir tablo, yani çok sayıda sütun var. Tüm sütunları elle yazmak zorunda kalmak istemiyorum. Bunu nasıl çalıştırabilirim?


zaten bu arada bağlantılı bir sunucu kurduk!
jhowe

4
Ben de bu sorunu yaşıyorum, dışında "X seç * Y eklemek" tablo şemasını değiştirene kadar bir sorun değildi
FistOfFury

Yanıtlar:


81

özet

SQL Server, bir sütun listesi kullanmadığınız sürece kimlik sütununa açık bir değer eklemenize izin vermez. Böylece, aşağıdaki seçeneklere sahipsiniz:

  1. Bir sütun listesi yapın (manuel olarak veya araçları kullanarak aşağıya bakın)

VEYA

  1. kimlik sütununu tbl_A_archivenormal, kimlik dışı bir sütunda yapın: Tablonuz bir arşiv tablosu ise ve her zaman kimlik sütunu için açık bir değer belirlerseniz, neden bir kimlik sütununa ihtiyacınız vardır? Bunun yerine normal bir int kullanın.

Çözüm 1 ile İlgili Ayrıntılar

Onun yerine

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

yazman gerek

SET IDENTITY_INSERT archive_table ON;

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

SET IDENTITY_INSERT archive_table OFF;

ile field1, field2, ...senin tablolardaki tüm sütunların adlarını içeren. Bu sütun listesini otomatik olarak oluşturmak istiyorsanız Dave'in cevabına veya Andomar'ın cevabına bir göz atın .


Çözüm 2 ile İlgili Ayrıntılar

Ne yazık ki, bir kimlik int sütununun "türünü" yalnızca kimlik dışı bir int sütununa değiştirmek mümkün değildir. Temel olarak, aşağıdaki seçeneklere sahipsiniz:

  • Arşiv tablosu henüz veri içermiyorsa, sütunu bırakın ve kimliği olmayan yeni bir tane ekleyin.

VEYA

  • Arşiv tablonuzdaki kimlik sütununun Identity Specification/ (Is Identity)özelliğini olarak ayarlamak için SQL Server Management Studio'yu kullanın No. Bu, perde arkasında, tabloyu yeniden oluşturmak ve mevcut verileri kopyalamak için bir komut dosyası yaratacağından, bunu yapmak için Tools/ Options/ Designers/ Table and Database Designers/ öğesinin ayarını da kaldırmanız gerekir Prevent saving changes that require table re-creation.

VEYA


1
En alt çözümünüze: Sütunda "IDENTITY (1, 1)" veya benzeri bir şey varsa, onu da geçici olarak kaldırması gerekir.
Aleksandr Khomenko

1
@AleksandrKhomenko: Evet, bunu "düzenli ( kimlik dışı ) bir int sütunu" yapmakla kastediyorum .
Heinzi

1
Karışıklık için özür dilerim. Aslında, otomatik artış özelliğini de kaldırması gerektiği anlamına geliyordu . SQL-Server durumunda "IDENTITY (1, 1)" olarak adlandırılır - cevabınız kesinlikle doğrudur. Ancak MySQL ve Oracle'ın bunun için başka komutları var (ve açıkça belli değil, lütfen w3schools.com/sql/sql_autoincrement.asp adresine bakın )
Aleksandr Khomenko

2
Bu detaylı bir şekilde eksik. Bazılarına karşı çürük olabileceğini anlıyorum ama başkalarına saçmalık
DJ.

1
@DJ .: Biraz detay ekledim.
Heinzi

332
SET IDENTITY_INSERT tableA ON

INSERT ifadeniz için bir sütun listesi oluşturmanız gerekir:

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

"SEÇİN Tabloya ekle Bir SELECT ........" gibi değil

SET IDENTITY_INSERT tableA OFF

17
+1 ... Sorgunun SELECT yan tümcesinde yalnızca açık sütunlara ihtiyacınız vardır. Sorgunun INSERT yan tümcesinde yıldız işareti tutabilirsiniz
MacGyver

8
... hedefte bir kimlik sütunu yoksa ve kaynak tablonun bir kimlik sütunu yoksa
MacGyver

1
bu cevap Heinzi'den biraz daha açık çünkü SET IDENTITY_INSERT'den bahsediyor
Marty

4
+1 Bir cazibe gibi çalışır! Ancak, "Sorgunun INSERT yan tümcesinde yıldız işareti tutabilirsiniz" burada çalışmaz.
Shai Alon

1
Select yan tümcesindeki sütunlar hedef tabloyla eşleşmediğinde bu hatayı aldım. Bundan emin olarak, insert benim için çalıştı
Jose

39

SQL Server Management Studio kullanıyorsanız, sütun listesini kendiniz yazmak zorunda değilsiniz - Nesne Gezgini'nde tabloya sağ tıklayın ve Komut Dosyası Tablosu -> SEÇ - -> Yeni Sorgu Düzenleyici Penceresi'ni seçin .

Eğer değilseniz, buna benzer bir sorgu başlangıç ​​noktası olarak yardımcı olacaktır:

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
Bu bir değişken olarak seçilebilir ve dinamik SQL sorgusunda kullanılabilir. Günümü kurtardın. Çok teşekkürler!
Pawel Cioch


vay. desperetaly dinamik olarak benim sorgu oluşturmak için arıyordu. Burada gördüğüme şaşırdım. Teşekkürler dostum.
Yasin Bilir

24

Heinzi'nin cevabı ile aynı fikirde. İlk ikinci seçenek için, bir tabloda virgülle ayrılmış sütun listesi oluşturan bir sorgu:

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

Büyük tablolar için, bu çok yazarak işten tasarruf edebilirsiniz :)


@ Teşekkürler, gerçekten yararlı. :)
Chirag Thakar

Bazen sadece pragmatik bir çözüme ihtiyacınız vardır. Teşekkür ederim!
Tobias Feil

15

"Arşiv" tablosu ana tablonuzun tam bir kopyası olması gerekiyorsa, o zaman sadece id bir kimlik sütunu olduğu gerçeğini kaldırmanızı öneririm. Bu şekilde onları yerleştirmenize izin verir.

Alternatif olarak, aşağıdaki ifadeyle tablo için kimlik eklerine izin verebilir ve izin vermeyebilirsiniz

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

Son olarak, olduğu gibi çalışmak için kimlik sütununa ihtiyacınız varsa, her zaman depolanan proc'u çalıştırabilirsiniz.

sp_columns tbl_A_archive 

Bu, tablodaki tüm sütunları döndürerek daha sonra kesip sorgunuza yapıştıracaktır. (Bu neredeyse HER ZAMAN a * kullanmaktan daha iyidir)


11

SQL deyimi için, sütun listesini de belirtmeniz gerekir. Örneğin.

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

onun yerine

INSERT INTO tbl VALUES ( value1,value2)

2
Bu OP'nin açıklaması için geçerli değildir. INSERT INTO öğesinin ardından bir SELECT ifadesi geliyorsa VALUES gerekli değildir. Lütfen yanıtınızı gözden geçirin veya kaldırın.
Gary

4

Her ikisi de işe yarayacak, ancak # 1'i kullanarak hala hata alıyorsanız # 2'ye gidin

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 birden fazla kayıt ekliyorsa, bu gerçekten işe yaramaz. "Tbl_A satır ve genişlikte büyük bir tablo, yani bir sürü sütun var. Tüm sütunları el ile yazmak zorunda kalmak istemiyorum."
Gary

4

Tüm sütun adlarını, bu soru için belirtilen çözümler için bir Select deyimi için virgülle ayrılmış bir listeye doldurmak amacıyla, buradaki yanıtların çoğundan biraz daha az ayrıntılı oldukları için aşağıdaki seçenekleri kullanıyorum. Bununla birlikte, buradaki yanıtların çoğu hala mükemmel bir şekilde kabul edilebilir.

1)

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

2) SQL Server SSMS'niz varsa, bu muhtemelen sütun oluşturmada en basit yaklaşımdır.

1) Nesne Gezgini'nde tabloya gidin ve tablo adının solundaki + işaretine tıklayın veya alt listeyi açmak için tablo adına çift tıklayın.

2) Sütun alt klasörünü ana sorgu alanına sürüklediğinizde sütun listesinin tamamı sizin için otomatik olarak oluşturulur.


3

Bir Kimlik sütunu varsa eklemek istediğiniz sütunların adını belirtmeniz gerekir. Yani komut aşağıdaki gibi olacaktır:

SET IDENTITY_INSERT DuplicateTable ON

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

SET IDENTITY_INSERT DuplicateTable OFF

Tablonuzda çok sayıda sütun varsa, bu komutu kullanarak bu sütunların adını alın.

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

(son virgül (',') kaldırıldıktan sonra) Sütun adının sonlarını kopyalamanız yeterlidir.


3

Bu çalışmalı. Sorununuzla karşılaştım:

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;

Ne yazık ki, Kimlik'i belirten kayıtlar eklemek için kimlik sütunu da dahil olmak üzere sütunların bir listesine ihtiyacınız var gibi görünüyor. Ancak , SELECT içindeki sütunları listelemeniz GEREKMEZ. As @Dave Cluderay kopyalayıp (eğer az 200000 karakter) yapıştırmak için bu biçimlendirilmiş bir listede neden olacaktır önerdi.

Örnekler arasında geçiş yaptığım için USE'yi ekledim.

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

Böyle değil

INSERT INTO tableA
SELECT * FROM tableB

SET IDENTITY_INSERT tableA OFF

2

Bu kod snippet'i, Kimlik Birincil Anahtar sütunu AÇIK olduğunda tabloya nasıl ekleneceğini gösterir.

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

Değerlerinizi saklı yordam aracılığıyla bir tablodan diğerine eklemek istiyorsanız. Ben kullanılan bu ve bu , neredeyse Andomar yanıt gibi olan ikincisi.

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

Otomatik artış özelliğine sahip bir veya daha fazla sütun var veya bu özelliğin değeri sınırlama olarak hesaplanacak. Bu sütunu değiştirmeye çalışıyorsunuz.

Bunu çözmenin iki yolu vardır 1) Diğer sütunları açıkça belirtin ve yalnızca değerlerini ayarlayın; PrimaryKey veya otomatik artan sütun değeri otomatik olarak ayarlanır.

2) INDENTITY_INSERT'yi açıp ekleme sorgunuzu yürütebilir ve sonunda IDENTITY_INSERT'yi kapatabilirsiniz.

Öneri: İlk adımı takip edin çünkü daha uygun ve verimli bir yaklaşımdır.

Daha fazla bilgi için SQL yardımcısı hakkındaki bu makaleyi okuyun .


0

Lütfen kayıtları seçtiğiniz tablodaki sütun adlarının, veri türlerinin ve sıralarının hedef tabloyla tamamen aynı olduğundan emin olun. Tek fark, hedef tablonun ilk sütun olarak bir kimlik sütunu olması, kaynak tabloda bulunmamasıdır.

"INSERT INTO table_Dest SELECT * FROM table_source_linked_server_excel" yürütürken benzer sorunla karşı karşıya kaldım. Tablolarda 115 sütun vardı.

Ben veritabanında tablolara Excel (bağlı sunucu olarak) veri yüklerken böyle iki tablo vardı. Veritabanı tablolarında, kaynak Excel'de olmayan 'id' adlı bir kimlik sütunu ekledim. Bir tablo için sorgu başarıyla çalışıyordu ve diğerinde "Tablodaki kimlik sütunu için açık bir değer yalnızca bir sütun listesi kullanıldığında ve IDENTITY_INSERT ON SQL Server olduğunda belirlenebilir" hatasını aldım. Senaryo her iki sorgu için de tam olarak aynı olduğu için bu şaşırtıcıydı. Bu yüzden araştırdım ve bulduğum sorguda INSERT INTO ile hata alıyordum oldu .. SELECT *:

  1. Kaynak tablodaki sütun adlarından bazıları değiştirildi, ancak değerler doğru
  2. SELECT * tarafından seçilen gerçek veri sütunlarının ötesinde bazı ekstra sütunlar vardı. Bunu kaynak Excel tablosunda (bağlantılı sunucular altında) "Komut dosyası tablosu> Seçmek için> yeni sorgu penceresi" seçeneğini kullanarak keşfettim. Veri içermese de, Excel'deki son sütundan hemen sonra bir gizli sütun vardı. Bu sütunu kaynak Excel tablosunda sildim ve kaydettim.

Yukarıdaki iki değişikliği yaptıktan sonra INSERT INTO ... SELECT * sorgusu başarıyla çalıştırıldı. Hedef tablodaki kimlik sütunu, eklenen her satır için beklendiği gibi kimlik değerleri oluşturdu.

Bu nedenle, hedef tablo kaynak tabloda bulunmayan bir kimlik sütununa sahip olsa da, kaynak ve hedefteki adlar, veri türleri ve sütun sırası tamamen aynı ise, INSERT INTO .. ​​SELECT * başarıyla çalışacaktır.

Umarım birine yardımcı olur.


-1

Bu hata tablo tanımındaki sütun sayısı ve ekleme sorgusunda sütun sayısı ile uyumsuzluk nedeniyle oluştuğunu düşünüyorum. Ayrıca, sütunun uzunluğu girilen değerle birlikte atlanır. Bu sorunu çözmek için sadece tablo tanımını gözden geçirin


Benim için çalıştı: Tasarımdan tabloya bir sütun eklemeyi unuttum, diğer cevapları denemeden önce bunu kontrol etmek için iyi bir şey.
Exel Gamboa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.