238 votes

Une valeur explicite pour la colonne d'identité dans la table ne peut être spécifiée que lorsqu'une liste de colonnes est utilisée et que IDENTITY_INSERT est ON SQL Server

J'essaie de faire cette requête

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

mais même après avoir couru

set identity_insert dbo.tbl_A_archive on

Je reçois ce message d'erreur

Une valeur explicite pour la colonne d'identité dans la table 'dbo.tbl_A_archive' ne peut être spécifiée que lorsqu'une liste de colonnes est utilisée et que IDENTITY_INSERT est ON.

tbl_A est un tableau énorme en lignes et en largeur, c'est-à-dire qu'il comporte BEAUCOUP de colonnes. Je ne veux pas avoir à taper toutes les colonnes manuellement. Comment faire pour que cela fonctionne ?

0 votes

J'ai déjà installé un serveur lié d'ailleurs !

4 votes

J'ai aussi ce problème, sauf que le "insert into X select * Y" n'était pas un problème jusqu'à ce que je change le schéma de la table.

354voto

Ehsan Points 489
SET IDENTITY_INSERT tableA ON

Vous devez établir une liste de colonnes pour votre instruction INSERT :

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

pas comme "INSERT Into tableA SELECT ........"

SET IDENTITY_INSERT tableA OFF

17 votes

+1 ... Vous n'avez besoin de colonnes explicites que dans la clause SELECT de la requête. Vous pouvez conserver un astérisque dans la clause INSERT de la requête.

9 votes

... à moins que la cible ait une colonne d'identité et que la table source n'ait pas de colonne d'identité.

1 votes

Cette réponse est un peu plus claire que celle de Heinzi car elle mentionne SET IDENTITY_INSERT

150voto

Heinzi Points 66519

Résumé

SQL Server ne vous laisse pas insérer une valeur explicite dans une colonne d'identité à moins que vous n'utilisiez une liste de colonnes. Ainsi, vous avez les options suivantes :

  1. Faites une liste de colonnes (manuellement ou à l'aide d'outils, voir ci-dessous).

OU

  1. faire la colonne d'identité dans tbl_A_archive un régulier, non-identité colonne : Si votre table est une table d'archives et que vous spécifiez toujours une valeur explicite pour la colonne d'identité, pourquoi avez-vous besoin d'une colonne d'identité ? Utilisez simplement un int normal à la place.

Détails sur la solution 1

Au lieu de

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

vous devez écrire

SET IDENTITY_INSERT archive_table ON;

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

SET IDENTITY_INSERT archive_table OFF;

avec field1, field2, ... contenant les noms de toutes les colonnes de vos tableaux. Si vous voulez générer automatiquement cette liste de colonnes, jetez un coup d'oeil à Réponse de Dave o Réponse d'Andomar .


Détails sur la solution 2

Malheureusement, il n'est pas possible de simplement "changer le type" d'une colonne int d'identité en une colonne int de non-identité. En gros, vous avez les options suivantes :

  • Si le tableau d'archives ne contient pas encore de données, supprimez la colonne et ajoutez-en une nouvelle sans identité.

OU

  • Utilisez SQL Server Management Studio pour définir le Identity Specification / (Is Identity) de la colonne d'identité dans votre table d'archives pour No . Dans les coulisses, cela créera un script pour recréer la table et copier les données existantes, donc, pour ce faire, vous devrez également désactivez Tools / Options / Designers / Table and Database Designers / Prevent saving changes that require table re-creation .

OU

1 votes

A votre solution de fond : Si la colonne a "IDENTITY (1, 1)" ou quelque chose comme ça, il devra la supprimer temporairement aussi.

1 votes

@AleksandrKhomenko : Oui, c'est ce que je voulais dire par "en faire une activité régulière ( non-identité ) int colonne" .

1 votes

Désolé pour la confusion. Je voulais dire en fait qu'il devra enlever le auto-incrémentation la propriété également. Dans le cas de SQL-Server, il s'agit de "IDENTITY (1, 1)" - votre réponse est tout à fait correcte. Mais MySQL et Oracle ont d'autres commandes pour cela (et cela n'est pas évident, veuillez consulter le site suivant w3schools.com/sql/sql_autoincrement.asp )

45voto

Dave Cluderay Points 4541

Si vous utilisez SQL Server Management Studio, vous n'avez pas besoin de taper la liste des colonnes vous-même - il suffit de cliquer avec le bouton droit de la souris sur la table dans la section Explorateur d'objets et choisissez script Tableau comme -> SELECT à -> Fenêtre de l'éditeur de nouvelles requêtes .

Si ce n'est pas le cas, une requête similaire à celle-ci devrait vous servir de point de départ :

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 votes

Cela peut être sélectionné dans une variable et utilisé dans une requête SQL dynamique. Vous avez sauvé ma journée. Merci beaucoup !

1 votes

Merci ! J'ai fait ceci avec elle gist.github.com/timabell/0ddd6a69565593f907c7

0 votes

J'étais désespérément à la recherche de cette fonctionnalité pour construire ma requête de manière dynamique. Je suis surpris de le voir ici. Merci mon ami.

29voto

Andomar Points 115404

Je suis d'accord avec la réponse de Heinzi. Pour la première deuxième option, voici une requête qui génère une liste de colonnes séparées par des virgules dans une table :

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

Pour les grandes tables, cela peut permettre d'économiser beaucoup de travail de saisie :)

0 votes

Merci, c'est très utile :)

0 votes

Parfois, il faut juste une solution pragmatique. Merci !

17voto

Robin Day Points 39440

Si la table "archive" est censée être une copie exacte de votre table principale, je vous suggère simplement de supprimer le fait que l'identifiant est une colonne d'identité. De cette façon, vous pourrez les insérer.

Alternativement, vous pouvez autoriser et interdire les insertions d'identité pour la table avec l'instruction suivante

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

Enfin, si vous avez besoin que la colonne d'identité fonctionne telle quelle, vous pouvez toujours simplement exécuter la procédure stockée.

sp_columns tbl_A_archive 

Vous obtiendrez ainsi toutes les colonnes de la table, que vous pourrez ensuite couper et coller dans votre requête. (C'est presque TOUJOURS mieux que d'utiliser un *)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X