Un valore esplicito per la colonna Identity nella tabella può essere specificato solo quando viene utilizzato un elenco di colonne e IDENTITY_INSERT è su SQL Server


187

Sto provando a fare questa domanda

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

ma anche dopo che ho corso

set identity_insert dbo.tbl_A_archive on

Ricevo questo messaggio di errore

Un valore esplicito per la colonna Identity nella tabella 'dbo.tbl_A_archive' può essere specificato solo quando viene utilizzato un elenco di colonne e IDENTITY_INSERT è ON.

tbl_Aè una tabella enorme di righe e larghezza, ovvero ha MOLTE colonne. Non voglio dover digitare manualmente tutte le colonne. Come posso farlo funzionare?


tra l'altro ho già installato un server collegato!
jhowe,

4
sto riscontrando anche questo problema, tranne che "inserire in X seleziona * Y" non è stato un problema fino a quando non ho cambiato lo schema della tabella
FistOfFury

Risposte:


81

Sommario

SQL Server non consente di inserire un valore esplicito in una colonna di identità a meno che non si utilizzi un elenco di colonne. Pertanto, hai le seguenti opzioni:

  1. Crea un elenco di colonne (manualmente o utilizzando gli strumenti, vedi sotto)

O

  1. crea la colonna identità in tbl_A_archiveuna normale colonna non identitaria : se la tua tabella è una tabella di archivio e specifichi sempre un valore esplicito per la colonna identità, perché hai bisogno anche di una colonna identità? Basta usare un int normale invece.

Dettagli sulla soluzione 1

Invece di

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

devi scrivere

SET IDENTITY_INSERT archive_table ON;

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

SET IDENTITY_INSERT archive_table OFF;

con field1, field2, ...contenere i nomi di tutte le colonne nelle tabelle. Se desideri generare automaticamente quell'elenco di colonne, dai un'occhiata alla risposta di Dave o alla risposta di Andomar .


Dettagli sulla soluzione 2

Sfortunatamente, non è possibile semplicemente "cambiare il tipo" di una colonna int identità in una colonna int non identità. Fondamentalmente, hai le seguenti opzioni:

  • Se la tabella di archivio non contiene ancora dati, rilascia la colonna e aggiungine una nuova senza identità.

O

  • Utilizzare SQL Server Management Studio per impostare la proprietà Identity Specification/ (Is Identity)della colonna identità nella tabella di archivio su No. Dietro le quinte, questo creerà uno script per ricreare la tabella e copiare i dati esistenti, quindi, per farlo, dovrai anche deselezionare Tools/ Options/ Designers/ Table and Database Designers/Prevent saving changes that require table re-creation .

O


1
Alla tua soluzione in fondo: se la colonna ha "IDENTITÀ (1, 1)" o qualcosa del genere, dovrà rimuoverlo anche temporaneamente.
Aleksandr Khomenko,

1
@AleksandrKhomenko: Sì, questo è ciò che intendevo per "rendere [it] una colonna int normale ( non identitaria )" .
Heinzi,

1
Dispiace per la confusione. Intendevo dire che avrebbe dovuto rimuovere anche la proprietà di auto-incremento . Nel caso di SQL Server chiama "IDENTITY (1, 1)" - la tua risposta è assolutamente giusta. Ma MySQL e Oracle hanno altri comandi (e non è ovvio, per favore guarda w3schools.com/sql/sql_autoincrement.asp )
Aleksandr Khomenko

2
Questo è carente nei dettagli. Capisco che potrebbe essere scontato per alcuni ma non ha senso per gli altri
DJ.

1
@DJ .: Ho aggiunto alcuni dettagli.
Heinzi,

332
SET IDENTITY_INSERT tableA ON

Devi creare un elenco di colonne per la tua dichiarazione INSERT:

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

non come "INSERT INto tableA SELECT ........"

SET IDENTITY_INSERT tableA OFF

17
+1 ... Hai solo bisogno di colonne esplicite nella clausola SELECT della query. Puoi tenere un asterisco nella clausola INSERT della query
MacGyver

8
... a meno che la destinazione non abbia una colonna identità e la tabella di origine non abbia una colonna identità
MacGyver,

1
questa risposta è un po 'più chiara di Heinzi perché menziona SET IDENTITY_INSERT
Marty

4
+1 Funziona come un fascino! Tuttavia, "È possibile mantenere un asterisco nella clausola INSERT della query" non funzionerà qui.
Shai Alon,

1
Ho ricevuto questo errore quando le colonne nella clausola select non corrispondevano alla tabella di destinazione. Assicurandomi, l'inserto ha funzionato per me
Jose

39

Se si utilizza SQL Server Management Studio, non è necessario digitare manualmente l'elenco di colonne: è sufficiente fare clic con il pulsante destro del mouse sulla tabella in Esplora oggetti e selezionare Tabella script come -> SELEZIONA per -> Nuova finestra dell'editor di query .

In caso contrario, una query simile a questa dovrebbe aiutare come punto di partenza:

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
Questo può essere selezionato in una variabile e utilizzato nella query SQL dinamica. Mi hai salvato la giornata. Molte grazie!
Pawel Cioch,


Wow. stavo disperatamente cercando questo per costruire la mia query in modo dinamico. Sorpreso di vederlo qui. Grazie compagno.
Yasin Bilir,

24

Concordo con la risposta di Heinzi. Per la prima seconda opzione, ecco una query che genera un elenco di colonne separato da virgole in una tabella:

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

Per i tavoli grandi, questo può risparmiare molto lavoro di battitura :)


@Grazie, davvero utile. :)
Chirag Thakar

A volte hai solo bisogno di una soluzione pragmatica. Grazie!
Tobias Feil

15

Se la tabella "archivio" è pensata per essere una copia esatta della tua tabella principale, ti suggerirei semplicemente di rimuovere il fatto che l'id è una colonna identiy. In questo modo ti permetterà di inserirli.

In alternativa è possibile consentire e non consentire l'inserimento di identità per la tabella con la seguente istruzione

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

Infine, se hai bisogno che la colonna Identity funzioni così com'è, puoi sempre eseguire il proc memorizzato.

sp_columns tbl_A_archive 

Questo ti restituirà tutte le colonne dalla tabella che puoi quindi tagliare e incollare nella tua query. (È quasi SEMPRE meglio dell'uso di un *)


11

Per l'istruzione SQL, è inoltre necessario specificare l'elenco di colonne. Per es.

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

invece di

INSERT INTO tbl VALUES ( value1,value2)

2
Questo non è il caso della dichiarazione del PO. VALUES non è richiesto se INSERT INTO è seguito da un'istruzione SELECT. Si prega di rivedere o rimuovere la risposta.
Gary,

4

Entrambi funzioneranno ma se si ottiene ancora un errore utilizzando il numero 1, selezionare il numero 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
Questo non è davvero il modo di procedere se l'OP sta inserendo più record. Stai ignorando "tbl_A è una tabella enorme di righe e larghezza, ovvero ha MOLTE colonne. Non voglio digitare tutte le colonne manualmente."
Gary,

4

Per popolare tutti i nomi delle colonne in un elenco delimitato da virgole per un'istruzione Select per le soluzioni menzionate per questa domanda, utilizzo le seguenti opzioni in quanto sono un po 'meno dettagliate della maggior parte delle risposte qui. Tuttavia, la maggior parte delle risposte qui sono comunque perfettamente accettabili.

1)

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

2) Questo è probabilmente l'approccio più semplice alla creazione di colonne, se si dispone di SQL Server SSMS.

1) Vai alla tabella in Esplora oggetti e fai clic sul + a sinistra del nome della tabella o fai doppio clic sul nome della tabella per aprire l'elenco secondario.

2) Trascina la sottocartella di colonna nell'area della query principale e eseguirà il backup automatico dell'intero elenco di colonne.


3

È necessario specificare il nome delle colonne che si desidera inserire se è presente una colonna Identità. Quindi il comando sarà così sotto:

SET IDENTITY_INSERT DuplicateTable ON

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

SET IDENTITY_INSERT DuplicateTable OFF

Se la tua tabella ha molte colonne, prendi il nome di quelle colonne usando questo comando.

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

(dopo aver rimosso l'ultima virgola (',')) Basta copiare il nome delle colonne precedenti.


3

Questo dovrebbe funzionare. Ho appena riscontrato il tuo problema:

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;

Sfortunatamente sembra che sia necessario un elenco delle colonne, inclusa la colonna Identity, per inserire i record che specificano l'identità. Tuttavia , NON DEVI elencare le colonne in SELECT. Come suggerito da @Dave Cluderay, questo comporterà un elenco formattato da copiare e incollare (se inferiore a 200000 caratteri).

Ho aggiunto USE poiché sto passando da un'istanza all'altra.

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

Non così

INSERT INTO tableA
SELECT * FROM tableB

SET IDENTITY_INSERT tableA OFF

2

Questo frammento di codice mostra come inserire nella tabella quando la colonna Chiave primaria identità è ATTIVATA.

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

Se vuoi inserire i tuoi valori da una tabella all'altra attraverso una procedura memorizzata. Ho usato questo e questo , quest'ultimo che è quasi come la risposta di 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

0

Esiste una o più colonne con proprietà di incremento automatico o il valore di tale attributo verrà calcolato come vincolo. Stai provando a modificare quella colonna.

Esistono due modi per risolverlo: 1) Menziona esplicitamente altre colonne e imposta solo i loro valori e il valore della colonna PrimaryKey o dell'incremento automatico verrà impostato automaticamente.

2) Puoi attivare INDENTITY_INSERT quindi eseguire la tua query di inserimento e infine disattivare IDENTITY_INSERT.

Suggerimento: seguire il primo passo perché è un approccio più adatto ed efficiente.

Per ulteriori informazioni leggi questo articolo su SQL-helper .


0

Assicurarsi che i nomi delle colonne, i tipi di dati e l'ordine nella tabella da cui si stanno selezionando i record siano esattamente gli stessi della tabella di destinazione. L'unica differenza dovrebbe essere che la tabella di destinazione ha una colonna identità come prima colonna, che non è presente nella tabella di origine.

Stavo affrontando un problema simile quando stavo eseguendo "INSERT INTO table_Dest SELECT * FROM table_source_linked_server_excel". I tavoli avevano 115 colonne.

Avevo due tabelle di questo tipo in cui caricavo dati da Excel (come server collegato) in tabelle nel database. Nelle tabelle del database, avevo aggiunto una colonna di identità denominata "id" che non era presente in Excel di origine. Per una tabella la query è stata eseguita correttamente e in un'altra ho ricevuto l'errore "Un valore esplicito per la colonna identità nella tabella può essere specificato solo quando viene utilizzato un elenco di colonne e IDENTITY_INSERT è su SQL Server". Questo era sconcertante in quanto lo scenario era esattamente lo stesso per entrambe le query. Quindi ho studiato questo e quello che ho scoperto è che nella query in cui stavo ottenendo errori con INSERT INTO .. ​​SELECT *:

  1. Alcuni nomi di colonne nella tabella di origine sono stati modificati, sebbene i valori fossero corretti
  2. Esistevano alcune colonne aggiuntive oltre alle colonne di dati effettive che venivano selezionate da SELECT *. L'ho scoperto usando l'opzione "Tabella script come> Seleziona in> nuova finestra di query" sulla tabella Excel di origine (sotto i server collegati). C'era una colonna nascosta subito dopo l'ultima colonna in Excel, sebbene non avesse alcun dato. Ho eliminato quella colonna nella tabella Excel di origine e l'ho salvata.

Dopo aver apportato le due modifiche precedenti, la query per INSERT INTO ... SELECT * è stata eseguita correttamente. La colonna identità nella tabella di destinazione ha generato valori di identità per ogni riga inserita come previsto.

Pertanto, anche se la tabella di destinazione può avere una colonna di identità che non è presente nella tabella di origine, INSERT INTO .. ​​SELECT * verrà eseguito correttamente se i nomi, i tipi di dati e l'ordine delle colonne nell'origine e nella destinazione sono esattamente gli stessi.

Spero che aiuti qualcuno.


-1

Penso che questo errore si verifichi a causa della mancata corrispondenza con il numero di colonne nella definizione della tabella e il numero di colonne nella query di inserimento. Anche la lunghezza della colonna viene omessa con il valore inserito. Quindi rivedi la definizione della tabella per risolvere questo problema


Ha funzionato per me: ho dimenticato di aggiungere una colonna alla tabella dal design, buona cosa da verificare prima di provare altre risposte.
Exel Gamboa,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.