MySQL lädt NULL-Werte aus CSV-Daten

167

Ich habe eine Datei, die 3 bis 4 Spalten mit numerischen Werten enthalten kann, die durch Komma getrennt sind. Leere Felder werden mit der Ausnahme definiert, wenn sie sich am Ende der Zeile befinden:

1,2,3,4,5
1,2,3,,5
1,2,3

Die folgende Tabelle wurde in MySQL erstellt:

+ ------- + -------- + ------ + ----- + --------- + ------- +
| Feld | Geben Sie | ein Null | Schlüssel | Standard | Extra |
+ ------- + -------- + ------ + ----- + --------- + ------- +
| eins | int (1) | JA | | NULL | |
| zwei | int (1) | JA | | NULL | |
| drei | int (1) | JA | | NULL | |
| vier | int (1) | JA | | NULL | |
| fünf | int (1) | JA | | NULL | |
+ ------- + -------- + ------ + ----- + --------- + ------- +

Ich versuche, die Daten mit dem Befehl MySQL LOAD zu laden:

LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE moo FIELDS 
TERMINATED BY "," LINES TERMINATED BY "\n";

Die resultierende Tabelle:

+ ------ + ------ + ------- + ------ + ------ +
| eins | zwei | drei | vier | fünf |
+ ------ + ------ + ------- + ------ + ------ +
| 1 | 2 | 3 | 4 | 5 |
| 1 | 2 | 3 | 0 | 5 |
| 1 | 2 | 3 | NULL | NULL |
+ ------ + ------ + ------- + ------ + ------ +

Das Problem liegt in der Tatsache, dass MySQL aus irgendeinem Grund nicht den Standardwert der Spalte (NULL) verwendet und Null verwendet, wenn ein Feld in den Rohdaten leer und nicht definiert ist. NULL wird korrekt verwendet, wenn das Feld insgesamt fehlt.

Leider muss ich zu diesem Zeitpunkt in der Lage sein, zwischen NULL und 0 zu unterscheiden, daher wäre jede Hilfe willkommen.

Danke S.

bearbeiten

Die Ausgabe von SHOW WARNINGS:

+ --------- + ------ + -------------------------------- ------------------------ +
| Level | Code | Nachricht |
+ --------- + ------ + -------------------------------- ------------------------ +
| Warnung | 1366 | Falscher ganzzahliger Wert: '' für Spalte 'vier' in Zeile 2 |
| Warnung | 1261 | Zeile 3 enthält nicht für alle Spalten Daten
| Warnung | 1261 | Zeile 3 enthält nicht für alle Spalten Daten
+ --------- + ------ + -------------------------------- ------------------------ +
Spiros
quelle
Bei solchen Datenschemaänderungen würde ich d6tstack verwenden, das alle Spalten vor dem Ausführen ausrichtet LOAD DATA. Weitere Informationen zu Änderungen des Datenschemas finden Sie im Abschnitt Beispiele für d6tstack SQL .
Citynorman

Antworten:

193

Dies wird tun, was Sie wollen. Es liest das vierte Feld in eine lokale Variable und setzt dann den tatsächlichen Feldwert auf NULL, wenn die lokale Variable eine leere Zeichenfolge enthält:

LOAD DATA INFILE '/tmp/testdata.txt'
INTO TABLE moo
FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n"
(one, two, three, @vfour, five)
SET four = NULLIF(@vfour,'')
;

Wenn sie möglicherweise alle leer sind, lesen Sie sie alle in Variablen und haben mehrere SET-Anweisungen wie folgt:

LOAD DATA INFILE '/tmp/testdata.txt'
INTO TABLE moo
FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n"
(@vone, @vtwo, @vthree, @vfour, @vfive)
SET
one = NULLIF(@vone,''),
two = NULLIF(@vtwo,''),
three = NULLIF(@vthree,''),
four = NULLIF(@vfour,'')
;
Duncan Lock
quelle
Theoretisch nehme ich an - aber es ist alles im Speicher und enthält nur winzige Datenmengen pro Zeile, also würde ich mir vorstellen, dass es infinitesimal wäre; Sie sollten es jedoch testen, wenn Sie der Meinung sind, dass es ein Problem sein könnte.
Duncan Lock
4
Diese Antwort gefällt mir sehr gut. Benutzer können leere Zeichenfolgen sehen, ''wenn sie eine CSV-Datei ( IFNULL(Col,'')in SELECT INTO OUTFILEAbfrage verwenden) für Excel herunterladen. Uploads akzeptieren sie jedoch als null, anstatt sich \Nin der CSV-Datei damit befassen zu müssen . Vielen Dank!
Chrisan
9
Für Daten habe ich 'NULLIF (STR_TO_DATE (@ date1, "% d /% m /% Y"), "0000-00-00") verwendet
Joaquín L. Robles
1
Ich habe eine CSV-Datei, die Nullen enthält 0, in die konvertiert werden soll NULL(da es nicht möglich ist, für die betreffenden Daten einen Nullwert zu haben), sowie leere Zeichenfolgen. Wie kann sichergestellt werden, dass sowohl Nullen als auch leere Zeichenfolgen in konvertiert werden NULL?
Paul Rougieux
Wenn sich die Nullwerte und leeren Zeichenfolgen in separaten Spalten befinden, führen Sie einfach die obigen Schritte für die leeren Zeichenfolgen und etwa Folgendes für die Nullen aus : nullif(@vone, 0).
Duncan Lock
136

Das MySQL-Handbuch sagt:

Beim Lesen von Daten mit LOAD DATA INFILE werden leere oder fehlende Spalten mit '' aktualisiert. Wenn Sie einen NULL-Wert in einer Spalte möchten, sollten Sie \ N in der Datendatei verwenden. Unter bestimmten Umständen kann auch das wörtliche Wort "NULL" verwendet werden.

Sie müssen also die Leerzeichen wie folgt durch \ N ersetzen:

1,2,3,4,5
1,2,3,\N,5
1,2,3
Janci
quelle
3
Vielen Dank für den Tipp - ich bin skeptisch, die Rohquelldaten zu bearbeiten, aber wenn dies der einzige Weg ist, werde ich es ausprobieren.
Spiros
7
Ich verstehe Ihre Skepsis, niemand bearbeitet gerne Rohdaten, es fühlt sich einfach nicht richtig an. Wenn Sie jedoch eine Minute darüber nachdenken, muss es eine Möglichkeit geben, zwischen NULL und leerer Zeichenfolge zu unterscheiden. Sollten leere Einträge in NULL-Werte übersetzt werden, benötigen Sie eine spezielle Sequenz für leere Zeichenfolgen. Es wäre schön, eine Möglichkeit zu haben, MySQL zu sagen, wie leere Einträge zu behandeln sind, so etwas wie LOAD DATA INFILE '/tmp/testdata.txt' IN TABLE moo TREAT BLANKS AS NULL ...
Janci
2
OK, aber wenn Sie haben, Fields enclosed by: "ist das "\N"von"name",\N,"stuff"
Jonathon
3
Ich kann überprüfen, dass zumindest für "phpMyAdmin 3.5.5" kein Stil von \Nals Bezeichnung akzeptiert wird NULL. Verwenden Sie stattdessen NULLwie in diesem Beispiel:"name","age",NULL,"other","stuff"
Jonathon
1
Wir haben MySQL 5.5.46-0 + deb8u1. Ich habe sowohl NULL als auch \ N ausprobiert und nur \ N hat für uns funktioniert.
Raphael75
6

Das Verhalten ist je nach Datenbankkonfiguration unterschiedlich. Im strengen Modus würde dies einen Fehler auslösen, sonst eine Warnung. Die folgende Abfrage kann zum Identifizieren der Datenbankkonfiguration verwendet werden.

mysql> show variables like 'sql_mode';
Dobi
quelle
Vielen Dank! Ich kratzte mir am Kopf und versuchte herauszufinden, warum das Importieren einer CSV mit leeren Spalten, die ich gestern erfolgreich auf den Produktionsserver importiert hatte, bei meiner brandneuen lokalen Installation nicht funktionierte - dies war die Antwort in meinem Fall!
Emma Burrows
3

Verarbeiten Sie Ihre Eingabe-CSV vor, um leere Einträge durch \ N zu ersetzen.

Versuch einer Regex: s / ,, /, \ n, / g und s /, $ /, \ N / g

Viel Glück.

Sam Goldman
quelle
1
Dieser Regex funktioniert teilweise, er löst keine sequentiellen leeren Einträge, zum Beispiel ,,,, wird, \ n ,, \ n, sollte verwendbar sein, wenn Sie ihn zweimal
ausführen
1
Fasst die Antwort und den vorherigen Kommentar zusammen. Folgendes funktionierte für mich in der Reihenfolge: sed -i / ,, /, \ N / g '$ Datei, sed -i / ,, /, / g' $ Datei, sed -i / \ N, $ / \ N / g '$ Datei,
Omar Khazamov
Ich würde dies gerne tun, aber mir ist nicht klar, wie Sie diesen regulären Ausdruck ausführen. Wenn Sie MySQL verwenden, um dies für die Datei auszuführen, ist dies die beste Lösung. Aber du sagst es nicht und ich möchte nicht viel Zeit damit verbringen, zu googeln, wie man etwas macht, das möglicherweise nicht möglich ist.
DonkeyKong
1

(Variable1, @ Variable2, ..) SET Variable2 = nullif (@ Variable2, '' oder '') >> Sie können eine beliebige Bedingung setzen

Sagte
quelle
0

Variablen anzeigen

Show variables like "`secure_file_priv`";

Hinweis: Bewahren Sie Ihre CSV-Datei an dem mit dem obigen Befehl angegebenen Speicherort auf.

create table assessments (course_code varchar(5),batch_code varchar(7),id_assessment int, assessment_type varchar(10), date int , weight int);

Hinweis: Hier enthält die dateSpalte ' ' einige leere Werte in der CSV-Datei.

LOAD DATA INFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/assessments.csv' 
INTO TABLE assessments
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '' 
LINES TERMINATED BY '\n' 
IGNORE 1 ROWS 
(course_code,batch_code,id_assessment,assessment_type,@date,weight)
SET date = IF(@date = '', NULL, @date);
Nirmal Silwal
quelle