BULK INSERT mit Identitätsspalte (Auto-Inkrement)

74

Ich versuche, Massendaten aus einer CSV-Datei in die Datenbank aufzunehmen.

In der Mitarbeitertabelle wird eine Spalte ID(PK) automatisch inkrementiert.

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

Ich benutze diese Abfrage:

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

CSV-Datei -

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

aber es führt zu dieser Fehlermeldung:

Fehler beim Konvertieren von Massenladedaten (Typfehlanpassung oder ungültiges Zeichen für die angegebene Codepage) für Zeile 2, Spalte 1 (ID).

Abhi
quelle
Können Sie bitte Ihre Beispieldaten in der CSV-Datei veröffentlichen
praveen
1
Ich habe nach dem KEEPIDENTITYDing gesucht ... danke!
Nrod
1
Dafür gibt es eigentlich eine sehr einfache Lösung. Erstellen Sie eine Ansicht, lassen Sie nur die ID-Spalte weg und fügen Sie sie dann in die Ansicht ein.
Charles Okwuagwu

Antworten:

49

BULK INSERT nicht direkt in Ihre realen Tabellen.

Ich würde immer

  1. Einfügen in eine Staging- Tabelle dbo.Employee_Staging(ohne IDENTITYSpalte) aus der CSV-Datei
  2. möglicherweise bearbeiten / bereinigen / bearbeiten Sie Ihre importierten Daten
  3. und kopieren Sie dann die Daten mit einer T-SQL-Anweisung wie folgt in die reale Tabelle:

    INSERT INTO dbo.Employee(Name, Address) 
       SELECT Name, Address
       FROM dbo.Employee_Staging
    
marc_s
quelle
1
Die Idee ist gut, aber gibt es einen bestimmten Grund, warum Sie eine Staging-Tabelle verwenden?
Abhi
7
@Abhi: Ich kann (1) die IDENTITY-Spalte entfernen, die Trauer verursacht, und (2) ich kann die Daten betrachten, möglicherweise bestimmte Zeilen entfernen, einige Zeilen aktualisieren, bevor ich sie tatsächlich in die reale Tabelle importiere.
marc_s
11
@marc_s Dies ist zwar ein guter Rat, beantwortet aber nicht die Frage. jwerts sollte wirklich die beste Antwort nehmen.
Mawburn
Guter allgemeiner Rat. Aber was tun Sie auch mit einer Staging-Tabelle, wenn Sie eine Aufzeichnung der Zeilennummer aus der Eingabedatei wünschen?
Desillusioniert
> BULK INSERT nicht direkt in Ihre realen Tabellen einfügen. - Dieser Hinweis gilt nur für MSSQL DB, es gibt keine derartigen Einschränkungen in z. B. Postgres
ARA1307
101

Fügen Sie der CSV-Datei eine ID-Spalte hinzu und lassen Sie sie leer:

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

Entfernen Sie das Schlüsselwort KEEPIDENTITY aus der Abfrage:

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

Das ID-Identitätsfeld wird automatisch inkrementiert.

Wenn Sie dem ID-Feld in der CSV Werte zuweisen, werden diese ignoriert, sofern Sie nicht das Schlüsselwort KEEPIDENTITY verwenden. Sie werden dann anstelle der automatischen Inkrementierung verwendet.

Josh Werts
quelle
Selbst mit einer Staging-Tabelle benötigen Sie so etwas, wenn Sie eine Aufzeichnung der Zeilennummer aus der Eingabedatei wünschen. Ich mag das!
Desillusioniert
Hallo @Josh Werts. Bisher war Ihre Lösung ein Segen für mich. Es funktioniert auf meiner lokalen Datenbank. Wenn ich jetzt mit Microsoft SQL Server Management Studio eine Verbindung zu einer Remote-Datenbank herstelle und den Befehl ausführe, wird die Fehlermeldung "Massenladen nicht möglich, da die Datei" D: \ data.csv "nicht geöffnet werden konnte. Betriebssystemfehlercode 21 ( Das Gerät ist nicht bereit). Muss sich die CSV-Datei auf demselben Server befinden, auf dem sich die
Datenbank
1
@FokwaBest - Ich würde mir vorstellen, dass der Remote-Server kein Konzept für Ihr D: -Laufwerk hat. Ich denke, Sie müssten einen Freigabeordner erstellen, auf den der Remote-Server Zugriff hat, und ihn dann auf diese Weise referenzieren ... so etwas wie \\ myshare \ data.csv. Ich bin hier kein Experte und arbeite wirklich nicht viel in SQL Server. Vielleicht kann jemand anderes antworten, wenn das nicht funktioniert.
Josh Werts
Die Lösung ist gut, aber was ist, wenn Sie die CSV-Dateien nicht aktualisieren können. Was ist in einem solchen Fall, wenn Sie die Datei herunterladen und in die Datenbank hochladen müssen?
Sadia
31

Ich hatte ein ähnliches Problem, musste aber sicherstellen, dass die Reihenfolge der ID mit der Reihenfolge in der Quelldatei übereinstimmt. Meine Lösung verwendet eine ANSICHT für das BULK INSERT:

Behalten Sie Ihre Tabelle bei und erstellen Sie diese ANSICHT (wählen Sie alles außer der ID-Spalte aus).

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

Ihr BULK INSERT sollte dann so aussehen:

BULK INSERT [dbo].[VW_Employee] FROM 'path\tempFile.csv ' 
WITH (FIRSTROW = 2,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');
Paul_S
quelle
2
Dies ist bei weitem die beste Lösung für diese Frage
DhruvJoshi
Ich bin damit einverstanden, dass dies der Weg ist, dies zu tun.
Derek Hackett
2
Der einfachste und einfachste Weg, eine Masseneinfügung in eine Staging-Tabelle auszuführen, die nicht mit der Quelldatei übereinstimmt. Allerdings habe ich heute gerade festgestellt, dass es anscheinend keine Garantie dafür gibt, dass die Daten in der Reihenfolge der Datei eingefügt werden. Welches ist ein Killer für den Import von Mainframe-Header / Detail-Typ-Dateien
Nick.McDermaid
9

Sie müssen eine Masseneinfügung mit der Formatdatei durchführen:

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

Dabei sieht die Formatdatei (tempFile.fmt) folgendermaßen aus:

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

Weitere Details finden Sie hier - http://msdn.microsoft.com/en-us/library/ms179250.aspx

Hotfusion
quelle
Dies sollte funktionieren. Lesen Sie die Dokumentation. Das Überspringen von Spalten wird behandelt, aber das Überspringen von PK-Spalten wird nicht speziell behandelt. In der Praxis muss ich dies ohne Fehler tun können: Nachricht 4866, Ebene 16, Status 7, Zeile 6 Die Massenladung ist fehlgeschlagen. Die Spalte in der Datendatei für Zeile 1, Spalte 1 ist zu lang. Stellen Sie sicher, dass der Feldabschluss und der Zeilenabschluss korrekt angegeben sind. Meldung 7301, Ebene 16, Status 2, Zeile 6 Die erforderliche Schnittstelle ("IID_IColumnsInfo") kann vom OLE DB-Anbieter "BULK" für den Verbindungsserver "(null)" nicht abgerufen werden.
sboggs11
2

Meine Lösung besteht darin, das ID-Feld als LETZTES Feld in der Tabelle hinzuzufügen, sodass das Masseneinfügen es ignoriert und automatische Werte erhält. Sauber und einfach ...

Zum Beispiel beim Einfügen in eine temporäre Tabelle:

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

Beachten Sie, dass das ROW_IDFeld immer als LAST-Feld angegeben werden muss!

Langbaba
quelle
Dies mag in einigen Situationen funktionieren, aber als ich dies versuchte, gab es mir nur einen leeren Tisch.
Bryce Wagner
scheint in 2008R2 nicht zu funktionieren. Ich erhalte den gleichen Fehler wie OP beim Masseneinfügen von 4 Spalten mit 4 Spalten in meiner Datendatei und einer 5. Identitätsspalte in der Zieltabelle. In error.txt Datei bekomme ich Row 2 File Offset 528 ErrorFile Offset 0 - HRESULT 0x80020005und in meinem stderr:msgtext = 'Bulk load data conversion error (type mismatch or invalid character for the specified codepage) for row 2, column 5 (QMid).'
mpag
1

Ich hatte genau das gleiche Problem, das zu Verluststunden führte, daher bin ich inspiriert, meine Erkenntnisse und Lösungen zu teilen, die für mich funktionierten.

1. Verwenden Sie eine Excel-Datei

Dies ist der Ansatz, den ich gewählt habe. Anstatt eine CSV-Datei zu verwenden, habe ich eine Excel-Datei (.xlsx) mit Inhalten wie unten verwendet.

id  username   email                token website

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

Beachten Sie, dass die ID-Spalte keinen Wert hat.

Stellen Sie als Nächstes mit Microsoft SQL Server Management Studio eine Verbindung zu Ihrer Datenbank her, klicken Sie mit der rechten Maustaste auf Ihre Datenbank und wählen Sie Daten importieren (Untermenü unter Aufgabe). Wählen Sie Microsoft Excel als Quelle. Wenn Sie die Stufe "Quellentabellen und -ansichten auswählen" erreicht haben, klicken Sie auf Zuordnungen bearbeiten . idKlicken Sie für die Spalte unter Ziel darauf und wählen Sie Ignorieren . Überprüfen Enable Identity insertSie dies nur, wenn Sie IDs beibehalten möchten, wenn Sie Daten aus einer anderen Datenbank importieren und die automatische Inkrementierungs-ID der Quelldatenbank beibehalten möchten. Fahren Sie fort, um fertig zu werden, und das war's. Ihre Daten werden reibungslos importiert.

2. Verwenden der CSV-Datei

Stellen Sie in Ihrer CSV-Datei sicher, dass Ihre Daten wie folgt sind.

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

Führen Sie die folgende Abfrage aus:

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

Das Problem bei diesem Ansatz besteht darin, dass sich die CSV auf dem DB-Server oder in einem freigegebenen Ordner befinden sollte, auf den die DB zugreifen kann. Andernfalls wird möglicherweise die Fehlermeldung "Datei kann nicht geöffnet werden. Das Betriebssystem hat den Fehlercode 21 zurückgegeben (Das Gerät ist nicht bereit) angezeigt ) ".

Wenn Sie eine Verbindung zu einer entfernten Datenbank herstellen, können Sie Ihre CSV in ein Verzeichnis auf diesem Server hochladen und auf den Pfad in der Masseneinfügung verweisen.

3. Verwenden der CSV-Datei und der Importoption von Microsoft SQL Server Management Studio

Starten Sie Ihre Importdaten wie im ersten Ansatz. Für Quelle, wählen Sie Flatfile - Quelle und suchen Sie nach Ihrer CSV - Datei. Stellen Sie sicher, dass das richtige Menü (Allgemein, Spalten, Erweitert, Vorschau) in Ordnung ist. Stellen Sie sicher, dass Sie das richtige Trennzeichen im Spaltenmenü (Spaltenbegrenzer) festlegen. Klicken Sie wie im obigen Excel-Ansatz auf Zuordnungen bearbeiten . Klicken Sie für die ID-Spalte unter Ziel darauf und wählen Sie Ignorieren .

Fahren Sie fort, um fertig zu werden, und das war's. Ihre Daten werden reibungslos importiert.

Fokwa Best
quelle
1
  1. Erstellen Sie eine Tabelle mit Identitätsspalte + anderen Spalten.
  2. Erstellen Sie eine Ansicht darüber und legen Sie nur die Spalten offen, die Sie als Masseneinfügung erstellen möchten.
  3. BCP in der Ansicht
user10513964
quelle
2
Willkommen bei Stack Overflow. Zu den besten Antworten gehören weitere Erklärungen dazu, wie hilfreich Ihre Antwort ist und möglicherweise, wie sich Ihre Antwort von anderen unterscheidet.
CGritton
1

Dies ist ein sehr alter Beitrag, der beantwortet werden muss, aber keine der gegebenen Antworten löst das Problem, ohne die gestellten Bedingungen zu ändern, was ich nicht tun kann.

Ich habe es mit der OPENROWSET-Variante von BULK INSERT gelöst. Dies verwendet dieselbe Formatdatei und funktioniert auf dieselbe Weise, ermöglicht jedoch das Lesen der Datendatei mit einer SELECT-Anweisung.

Erstellen Sie Ihre Tabelle:

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

Öffnen Sie ein Befehlsfenster und führen Sie Folgendes aus:

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

Dadurch wird die Formatdatei basierend auf dem Aussehen der Tabelle erstellt.

Bearbeiten Sie nun die Formatdatei und entfernen Sie die gesamten Zeilen mit FIELD ID = "1" und COLUMN SOURCE = "1", da dies in unserer Datendatei nicht vorhanden ist.
Passen Sie auch die Terminatoren an, die für Ihre Datendatei erforderlich sind:

<?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>

Jetzt können wir die Datendatei mit einer Auswahl in unsere Tabelle laden und so die volle Kontrolle über die Spalten haben. In diesem Fall können wir keine Daten in die Identitätsspalte einfügen:

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

Eine andere Option, wenn Sie temporäre Tabellen anstelle von Staging-Tabellen verwenden, besteht darin, die temporäre Tabelle wie beim Import erwartet zu erstellen und nach dem Import die Identitätsspalte hinzuzufügen.

Ihr SQL macht also ungefähr so:

  1. Wenn eine temporäre Tabelle vorhanden ist, löschen Sie diese
  2. Erstellen Sie eine temporäre Tabelle
  3. Massenimport in temporäre Tabelle
  4. Temp-Tabelle ändern Identität hinzufügen
  5. <was auch immer Sie mit den Daten machen wollen>
  6. Temp-Tabelle löschen

Immer noch nicht sehr sauber, aber es ist eine andere Option ... muss möglicherweise auch Schlösser bekommen, um sicher zu sein.

Izzy
quelle