2010-04-20 8 views
131

J'ai un fichier qui peut contenir de 3 à 4 colonnes de valeurs numériques séparées par une virgule. Les champs vides sont définis à l'exception quand ils sont à la fin de la ligne:MySQL charge les valeurs NULL à partir des données CSV

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

Le tableau suivant a été créé en MySQL:

 
+-------+--------+------+-----+---------+-------+ 
| Field | Type | Null | Key | Default | Extra | 
+-------+--------+------+-----+---------+-------+ 
| one | int(1) | YES |  | NULL |  | 
| two | int(1) | YES |  | NULL |  | 
| three | int(1) | YES |  | NULL |  | 
| four | int(1) | YES |  | NULL |  | 
| five | int(1) | YES |  | NULL |  | 
+-------+--------+------+-----+---------+-------+ 

Je suis en train de charger les données en utilisant la commande MySQL LOAD :

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

Le tableau résultant:

 
+------+------+-------+------+------+ 
| one | two | three | four | five | 
+------+------+-------+------+------+ 
| 1 | 2 |  3 | 4 | 5 | 
| 1 | 2 |  3 | 0 | 5 | 
| 1 | 2 |  3 | NULL | NULL | 
+------+------+-------+------+------+ 

Le problème réside dans le fait que lorsqu'un champ est vide dans les données brutes et n'est pas défini, MySQL n'utilise pas la valeur par défaut des colonnes (qui est NULL) et utilise zéro. NULL est utilisé correctement lorsque le champ est manquant tous ensemble.

Malheureusement, je dois être capable de distinguer entre NULL et 0 à ce stade, donc toute aide serait appréciée.

Merci S.

modifier

La sortie SHOW WARNINGS:

 
+---------+------+--------------------------------------------------------+ 
| Level | Code | Message            | 
+---------+------+--------------------------------------------------------+ 
| Warning | 1366 | Incorrect integer value: '' for column 'four' at row 2 | 
| Warning | 1261 | Row 3 doesn't contain data for all columns    | 
| Warning | 1261 | Row 3 doesn't contain data for all columns    | 
+---------+------+--------------------------------------------------------+ 

Répondre

139

Cela va faire ce que vous voulez. Il lit le quatrième champ dans une variable locale, et définit la valeur réelle du champ à NULL, si la fin variable locale contenant jusqu'à une chaîne vide:

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

S'ils sont tous peut-être vide, alors vous lire tous en variables et ont plusieurs instructions SET, comme ceci:

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

a-t-il un impact sur les performances? – Blacksonic

+0

Théoriquement, je suppose - mais tout est en mémoire, et ne contenant que de petites quantités de données par rangée, donc j'imaginerais que ce serait infinitésimal, mais vous devriez le tester si vous pensez que cela pourrait être un problème –

+2

J'aime vraiment cette réponse. Les utilisateurs peuvent voir des chaînes vides '''' quand ils téléchargent un csv (en utilisant 'IFNULL (Col, '')' dans la requête 'SELECT INTO OUTFILE') pour excel mais ensuite les uploads les acceptent comme null par rapport à \ N 'dans le csv. Merci! – chrisan

2

Prétraitez votre CSV d'entrée pour remplacer les entrées vides avec \ N.

Tentative de regex: s/,, /, \ n,/g et s /, $ /, \ N/g

Bonne chance.

+1

Ce regex fonctionne partiellement, il ne résout pas les entrées vides séquentiels, par exemple ,,,, sera, \ n ,, \ n, devrait être utilisable si vous exécutez deux fois – ievgen

+0

résumerai la réponse et commentaire précédent. Suite travaillé pour moi, dans l'ordre: sed -i 's/,, /, \ N/g' $ fichier, sed -i 's/,, /, g' $ fichier, sed -i ' s/\ N, $/\ N/g '$ fichier, –

95

MySQL manual dit:

Lors de la lecture des données avec LOAD DATA INFILE, les colonnes vides ou manquantes à jour avec ''. Si vous souhaitez une valeur NULL dans une colonne, vous devez utiliser \ N dans le fichier de données. Le mot littéral "NULL" peut également être utilisé dans certaines circonstances .

Vous devez remplacer les blancs avec \ N comme ceci:

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

Merci pour le conseil - Je suis sceptique pour éditer les données de la source brute mais si c'est le seul moyen de contourner cela, je vais essayer. – Spiros

+7

Je comprends votre scepticisme, personne n'aime modifier les données brutes, ça ne me semble pas juste. Cependant, si vous y réfléchissez un instant, il doit y avoir un moyen de faire la distinction entre une chaîne vide et une chaîne vide. Si les entrées vides sont traduites en valeurs NULL, vous aurez besoin d'une séquence spéciale pour la chaîne vide. Il serait bien d'avoir un moyen de dire à MySQL comment traiter les entrées vierges, comme quelque chose comme LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE MOO TRAAT BLANKS COMME NULL ... – Janci

+2

OK, mais si vous avez 'Champs entouré par: "' est ce '' \ N "' de '" nom ", \ N," stuff "' – Jonathon

5

le comportement est différent en fonction de la configuration de base de données. En mode strict cela jetterait une erreur sinon un avertissement. La requête suivante peut être utilisée pour identifier la configuration de la base de données.

mysql> show variables like 'sql_mode'; 
+0

Merci! Je me grattais la tête en essayant de comprendre pourquoi l'importation d'un CSV avec des colonnes vides que j'avais importées avec succès sur le serveur de production hier ne fonctionnait pas sur ma toute nouvelle installation locale - c'était la réponse dans mon cas! –