web-dev-qa-db-fra.com

BULK INSERT avec la colonne d'identité (incrémentation automatique)

J'essaie d'ajouter des données en vrac dans la base de données à partir d'un fichier CSV.

La table des employés a une colonne ID (PK) auto-incrémentée.

CREATE TABLE [dbo].[Employee](
 [id] [int] IDENTITY(1,1) NOT NULL,
 [Name] [varchar](50) NULL,
 [Address] [varchar](50) NULL
) ON [PRIMARY]

J'utilise cette requête:

BULK INSERT Employee  FROM 'path\tempFile.csv ' 
WITH (FIRSTROW = 2,KEEPIDENTITY,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');

Fichier CSV -

Name,Address
name1,addr test 1
name2,addr test 2

mais il en résulte ce message d'erreur:

Erreur de conversion des données de chargement en bloc (incompatibilité de type ou caractère non valide pour la page de codes spécifiée) pour la ligne 2, colonne 1 (id).

58
Abhi

N'insérez pas directement dans vos real tables.

Je voudrais toujours 

  1. insérer dans un staging table dbo.Employee_Staging (sans la colonne IDENTITY) à partir du fichier CSV
  2. éventuellement éditer/nettoyer/manipuler vos données importées
  3. puis copiez les données dans la table réelle avec une instruction T-SQL telle que:

    INSERT INTO dbo.Employee(Name, Address) 
       SELECT Name, Address
       FROM dbo.Employee_Staging
    
39
marc_s

Ajoutez une colonne id au fichier csv et laissez-la vide:

id,Name,Address
,name1,addr test 1
,name2,addr test 2

Enlevez le mot-clé KEEPIDENTITY de la requête:

BULK INSERT Employee  FROM 'path\tempFile.csv ' 
WITH (FIRSTROW = 2,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');

Le champ d'identité sera automatiquement incrémenté.

Si vous attribuez des valeurs au champ id dans le fichier csv, elles seront ignorées à moins que vous n'utilisiez le mot clé KEEPIDENTITY. Elles seront utilisées à la place d'incrémentation automatique.

89
Josh Werts

J'avais un problème similaire, mais je devais m'assurer que l'ordre de l'ID est aligné sur celui du fichier source . Ma solution utilise une vue pour l'insertion de bloc:

Gardez votre table telle quelle et créez cette VUE (sélectionnez tout sauf la colonne ID)

CREATE VIEW [dbo].[VW_Employee]
AS
SELECT [Name], [Address]
FROM [dbo].[Employee];

Votre INSCRIPTION EN VRAC devrait alors ressembler à:

BULK INSERT [dbo].[VW_Employee] FROM 'path\tempFile.csv ' 
WITH (FIRSTROW = 2,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');
23
Paul_S

Vous devez faire une insertion en bloc avec un fichier de format:

   BULK INSERT Employee FROM 'path\tempFile.csv ' 
   WITH (FORMATFILE = 'path\tempFile.fmt');

où le fichier de format (tempFile.fmt) ressemble à ceci:

11.0
2
1 SQLCHAR 0 50 "\ t" 2 Nom SQL_Latin1_General_CP1_CI_AS
2 SQLCHAR 0 50 "\ r\n" 3 Adresse SQL_Latin1_General_CP1_CI_AS

plus de détails ici - http://msdn.Microsoft.com/en-us/library/ms179250.aspx

6
hotfusion

Ma solution consiste à ajouter le champ ID en tant que champ LAST dans la table. Ainsi, l'insertion en bloc l'ignore et obtient des valeurs automatiques. Propre et simple ...

Par exemple, si vous insérez dans une table temporaire:

CREATE TABLE #TempTable 
(field1 varchar(max), field2 varchar(max), ... 
ROW_ID int IDENTITY(1,1) NOT NULL)

Notez que le champ ROW_ID DOIT toujours être spécifié comme le dernier champ!

2
Langbaba
  1. Créer une table avec une colonne Identity + d'autres colonnes;
  2. Créez une vue dessus et n'exposez que les colonnes que vous allez insérer en bloc;
  3. BCP dans la vue
0
user10513964

J'avais exactement le même problème qui faisait perdre des heures, je suis donc inspiré par le partage de mes découvertes et des solutions qui ont fonctionné pour moi.

1. Utilisez un fichier Excel

C'est l'approche que j'ai adoptée. Au lieu d'utiliser un fichier csv, j'ai utilisé un fichier Excel (.xlsx) avec un contenu comme ci-dessous.

id  username   email                token website

    johndoe   [email protected]        divostar.com
    bobstone  [email protected]        divosays.com

Notez que la colonne id n'a aucune valeur. 

Ensuite, connectez-vous à votre base de données à l'aide de Microsoft SQL Server Management Studio, cliquez avec le bouton droit de la souris sur votre base de données et sélectionnez importer des données (sous-menu sous tâche). Sélectionnez Microsoft Excel comme source. Lorsque vous arrivez à l'étape appelée "Sélectionner les tables et les vues sources", cliquez sur éditer les mappages . Pour la colonne id sous la destination, cliquez dessus et sélectionnez ignore . Ne cochez pas Enable Identity insert sauf si vous souhaitez conserver les identifiants dans les cas où vous importez des données d'une autre base de données et que vous souhaitez conserver l'identifiant d'incrémentation automatique de la base de données source. Continuez pour finir et c'est tout. Vos données seront importées en douceur.

2. Utiliser un fichier CSV

Dans votre fichier csv, assurez-vous que vos données sont comme ci-dessous.

id,username,email,token,website
,johndoe,[email protected],,divostar.com
,bobstone,[email protected],,divosays.com

Exécutez la requête ci-dessous:

BULK INSERT Metrics FROM 'D:\Data Management\Data\CSV2\Production Data 2004 - 2016.csv '
WITH (FIRSTROW = 2, FIELDTERMINATOR = ',', ROWTERMINATOR = '\n');

Le problème avec cette approche est que le fichier CSV doit se trouver dans le serveur de base de données ou dans un dossier partagé auquel la base de données peut accéder. Sinon, vous risquez de recevoir une erreur du type "Fichier impossible à ouvrir. Le système d'exploitation a renvoyé le code d'erreur 21 (le périphérique n'est pas prêt ) ".

Si vous vous connectez à une base de données distante, vous pouvez alors télécharger votre fichier CSV dans un répertoire de ce serveur et référencer le chemin d'accès dans une insertion en bloc.

3. Utilisation d'un fichier CSV et de l'option d'importation Microsoft SQL Server Management Studio

Lancez vos données d'importation comme dans la première approche. Pour la source, sélectionnez Fichier plat Source et recherchez votre fichier CSV. Assurez-vous que le bon menu (Général, Colonnes, Avancé, Aperçu) est correct. Veillez à définir le séparateur de droite dans le menu des colonnes (Délimiteur de colonne). Tout comme dans l'approche Excel ci-dessus, cliquez sur modifier les correspondances . Pour la colonne id sous destination, cliquez dessus et sélectionnez ignore .

Continuez pour finir et c'est tout. Vos données seront importées en douceur.

0
Fokwa Best

Une autre option, si vous utilisez des tables temporaires au lieu de tables intermédiaires, pourrait être de créer la table temporaire comme le prévoit votre importation, puis d'ajouter la colonne d'identité après l'importation.

Donc, votre sql fait quelque chose comme ça: 

  1. Si la table temporaire existe, déposez
  2. Créer une table temporaire
  3. Importation en bloc dans la table temporaire
  4. Modifier la table temporaire ajouter une identité
  5. <tout ce que vous voulez faire avec les données>
  6. Drop temp table

Toujours pas très propre, mais c’est une autre option… il faudra peut-être aussi avoir des serrures pour être en sécurité. 

0
Izzy

C'est un très vieux message à répondre, mais aucune des réponses données ne résout le problème sans changer les conditions posées, ce que je ne peux pas faire.

Je l'ai résolu en utilisant la variante OPENROWSET de BULK INSERT. Ceci utilise le même fichier de format et fonctionne de la même manière, mais permet de lire le fichier de données avec une instruction SELECT.

Créez votre table:

CREATE TABLE target_table(
id bigint IDENTITY(1,1),
col1 varchar(256) NULL,
col2 varchar(256) NULL,
col3 varchar(256) NULL)

Ouvrez une fenêtre de commande et une exécution:

bcp dbname.dbo.target_table format nul -c -x -f C:\format_file.xml -t; -T

Cela crée le fichier de format basé sur l'apparence de la table.

Maintenant, éditez le fichier de format et supprimez toutes les lignes où FIELD ID = "1" et COLUMN SOURCE = "1", car cela n'existe pas dans notre fichier de données.
Ajustez également les terminaisons selon vos besoins pour votre fichier de données:

<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.Microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <RECORD>
  <FIELD ID="2" xsi:type="CharTerm" TERMINATOR=";" MAX_LENGTH="256" COLLATION="Finnish_Swedish_CI_AS"/>
  <FIELD ID="3" xsi:type="CharTerm" TERMINATOR=";" MAX_LENGTH="256" COLLATION="Finnish_Swedish_CI_AS"/>
  <FIELD ID="4" xsi:type="CharTerm" TERMINATOR="\r\n" MAX_LENGTH="256" COLLATION="Finnish_Swedish_CI_AS"/>
 </RECORD>
 <ROW>
  <COLUMN SOURCE="2" NAME="col1" xsi:type="SQLVARYCHAR"/>
  <COLUMN SOURCE="3" NAME="col2" xsi:type="SQLVARYCHAR"/>
  <COLUMN SOURCE="4" NAME="col3" xsi:type="SQLVARYCHAR"/>
 </ROW>
</BCPFORMAT>

Maintenant, nous pouvons charger en bloc le fichier de données dans notre table avec une sélection, ce qui permet un contrôle total sur les colonnes, dans ce cas en n'insérant pas de données dans la colonne d'identité:

INSERT INTO target_table (col1,col2, col3)
SELECT * FROM  openrowset(
bulk 'C:\data_file.txt',
formatfile='C:\format_file.xml') as t;
0
whetstone