MySQL carica valori NULL dai dati CSV


167

Ho un file che può contenere da 3 a 4 colonne di valori numerici che sono separati da una virgola. I campi vuoti vengono definiti con l'eccezione quando si trovano alla fine della riga:

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

La seguente tabella è stata creata in MySQL:

+ ------- + -------- + ------ + ----- + --------- + ------- +
| Campo | Digita | Null | Chiave | Predefinito | Extra |
+ ------- + -------- + ------ + ----- + --------- + ------- +
| uno | int (1) | SÌ | | NULL | |
| due | int (1) | SÌ | | NULL | |
| tre | int (1) | SÌ | | NULL | |
| quattro | int (1) | SÌ | | NULL | |
| cinque | int (1) | SÌ | | NULL | |
+ ------- + -------- + ------ + ----- + --------- + ------- +

Sto cercando di caricare i dati utilizzando il comando LOAD MySQL:

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

La tabella risultante:

+ ------ + ------ + ------- + ------ + ------ +
| uno | due | tre | quattro | cinque |
+ ------ + ------ + ------- + ------ + ------ +
| 1 | 2 | 3 | 4 | 5 |
| 1 | 2 | 3 | 0 | 5 |
| 1 | 2 | 3 | NULL | NULL |
+ ------ + ------ + ------- + ------ + ------ +

Il problema sta nel fatto che quando un campo è vuoto nei dati non elaborati e non è definito, MySQL per qualche motivo non utilizza il valore predefinito delle colonne (che è NULL) e usa zero. NULL viene utilizzato correttamente quando il campo manca del tutto.

Sfortunatamente, devo essere in grado di distinguere tra NULL e 0 in questa fase, quindi qualsiasi aiuto sarebbe apprezzato.

Grazie S.

modificare

L'output di SHOW WARNINGS:

+ --------- + ------ + -------------------------------- ------------------------ +
| Livello | Codice | Messaggio |
+ --------- + ------ + -------------------------------- ------------------------ +
| Avvertenza | 1366 | Valore intero errato: '' per la colonna 'quattro' alla riga 2 |
| Avvertenza | 1261 | La riga 3 non contiene dati per tutte le colonne |
| Avvertenza | 1261 | La riga 3 non contiene dati per tutte le colonne |
+ --------- + ------ + -------------------------------- ------------------------ +

Con modifiche allo schema dei dati del genere userei d6tstack che allinea tutte le colonne prima di eseguire LOAD DATA. Vedere la sezione Esempi SQL d6tstack sulle modifiche allo schema dei dati.
citynorman,

Risposte:


193

Questo farà quello che vuoi. Legge il quarto campo in una variabile locale e quindi imposta il valore del campo effettivo su NULL, se la variabile locale finisce per contenere una stringa vuota:

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,'')
;

Se sono tutti probabilmente vuoti, li leggeresti tutti in variabili e avresti più istruzioni SET, come questo:

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,'')
;

Teoricamente, suppongo, ma è tutto in memoria, e contiene solo minuscole quantità di dati per riga, quindi immagino che sarebbe infinitesimale; ma dovresti testarlo se pensi che potrebbe essere un problema.
Duncan Lock,

4
Mi piace molto questa risposta. Gli utenti possono vedere stringhe vuote ''quando scaricano un csv (usando IFNULL(Col,'')in SELECT INTO OUTFILEquery) per Excel ma poi i caricamenti li accettano come nulli rispetto a quelli da gestire \Nnel CSV. Grazie!
chrisan,

9
per le date che ho usato 'NULLIF (STR_TO_DATE (@ date1, "% d /% m /% Y"), "0000-00-00")'
Joaquín L. Robles,

1
Ho un file CSV che contiene zeri 0che dovrebbero essere convertiti NULL(perché non è possibile avere un valore zero per i dati in questione) e anche stringhe vuote. Come assicurarsi che sia gli zeri che le stringhe vuote vengano convertiti NULL?
Paul Rougieux,

Se i valori zero e le stringhe vuote sono in colonne separate, poi basta fare quanto sopra per le stringhe vuote, e qualcosa di simile per gli zeri: nullif(@vone, 0).
Duncan Lock,

136

Il manuale di MySQL dice:

Quando si leggono i dati con LOAD DATA INFILE, le colonne vuote o mancanti vengono aggiornate con ''. Se si desidera un valore NULL in una colonna, è necessario utilizzare \ N nel file di dati. La parola letterale "NULL" può anche essere usata in alcune circostanze.

Quindi è necessario sostituire gli spazi vuoti con \ N in questo modo:

1,2,3,4,5
1,2,3,\N,5
1,2,3

3
Grazie per il suggerimento: sono scettico di modificare i dati di origine grezzi, ma se questo è l'unico modo per provarlo, lo proverò.
Spiros,

7
Capisco il tuo scetticismo, a nessuno piace modificare i dati grezzi, semplicemente non sembra giusto. Tuttavia, se ci pensi per un minuto, ci deve essere un modo per distinguere tra NULL e stringa vuota. Se le voci vuote fossero tradotte in NULL, sarebbe necessaria una sequenza speciale per stringa vuota. Sarebbe bello avere un modo per dire a MySQL come trattare le voci vuote, qualcosa come LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE moo TREAT BLANKS AS NULL ...
Janci

2
OK, ma se hai Fields enclosed by: "quello "\N"di"name",\N,"stuff"
Jonathon

3
Posso verificare che almeno per "phpMyAdmin 3.5.5" nessuno stile di \Nè accettato come denotazione NULL. Invece usa NULL, come in questo esempio:"name","age",NULL,"other","stuff"
Jonathon

1
Abbiamo MySQL 5.5.46-0 + deb8u1. Ho provato sia NULL che \ N, e solo \ N ha funzionato per noi.
raphael75,

6

Il comportamento è diverso a seconda della configurazione del database. In modalità rigorosa, ciò genererebbe un errore, altrimenti un avviso. La seguente query può essere utilizzata per identificare la configurazione del database.

mysql> show variables like 'sql_mode';

Grazie! Mi stavo grattando la testa cercando di capire perché importare un CSV con colonne vuote che ieri avevo importato con successo sul server di produzione non funzionava sulla mia nuovissima installazione locale: questa era la risposta nel mio caso!
Emma Burrows,

3

Pre-elabora il CSV di input per sostituire le voci vuote con \ N.

Tentativo di regex: s / ,, /, \ n, / ge s /, $ /, \ N / g

In bocca al lupo.


1
Questo regex funziona parzialmente, non risolve le voci vuote sequenziali, ad esempio ,,,, sarà, \ n ,, \ n, Dovrebbe essere utilizzabile se lo esegui due volte
ievgen,

1
Riassumerà la risposta e il commento precedente. Di seguito ha funzionato per me, nell'ordine: sed -i 's / ,, /, \ N / g' $ file, sed -i 's / ,, /, / g' $ file, sed -i 's / \ N, $ / \ N / g '$ file,
Omar Khazamov,

Vorrei farlo, ma non sono chiaro su come stai eseguendo questa regex. Se stai usando MySQL per eseguirlo sul file, questa sarebbe la soluzione migliore. Ma non dici e non voglio passare un sacco di tempo a cercare su Google come fare qualcosa che potrebbe non essere possibile.
DonkeyKong,

1

(variabile1, @ variabile2, ..) SET variabile2 = nullif (@ variabile2, '' o '') >> puoi mettere qualsiasi condizione


0

mostra variabili

Show variables like "`secure_file_priv`";

Nota: mantenere il file CSV nella posizione indicata dal comando precedente.

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

Nota: qui la datecolonna ' ' ha alcuni valori vuoti nel file CSV.

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);
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.