2010-04-20 31 views
131

Tengo un archivo que puede contener de 3 a 4 columnas de valores numéricos que están separados por comas. Los campos vacíos se definen con la excepción cuando se encuentran al final de la fila:MySQL carga valores NULL de datos CSV

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

En la siguiente tabla se creó 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 |  | 
+-------+--------+------+-----+---------+-------+ 

Estoy tratando de cargar los datos mediante el comando CARGA MySQL :

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

La tabla resultante:

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

El problema radica en el hecho de que cuando un campo está vacío en los datos brutos y no está definido, MySQL por alguna razón no usa el valor predeterminado de las columnas (que es NULO) y usa cero. NULL se usa correctamente cuando el campo falta por completo.

Lamentablemente, tengo que ser capaz de distinguir entre NULL y 0 en esta etapa por lo que cualquier ayuda sería apreciada.

Gracias S.

edición

la salida de SHOW ADVERTENCIAS:

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

Respuesta

139

Esto va a hacer lo que quiere. Se lee el cuarto campo en una variable local, y selecciona el valor real del campo en NULL, si la variable local termina contiene una cadena vacía:

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

Si todos son posiblemente vacía, entonces sería léelos todos en variables y tenga varias sentencias SET, como esta:

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

¿tiene un impacto en el rendimiento? – Blacksonic

+0

Teóricamente, supongo, pero está todo en la memoria y solo contiene pequeñas cantidades de datos. por fila, por lo que imagino que sería infinitesimal, pero debe probarlo si cree que podría ser un problema. –

+2

Me gusta mucho esta respuesta. Los usuarios pueden ver las cadenas vacías '''' cuando descargan un csv (usando 'IFNULL (Col, '')' en la consulta 'SELECT INTO OUTFILE') para excel, pero luego las cargas las aceptan como nulas frente a' \ N 'en la csv. ¡Gracias! – chrisan

2

preproceso CSV de entrada para reemplazar las entradas en blanco con \ N.

Intento de una expresión regular: s/,, /, \ n,/gy s /, $ /, \ N/g

Buena suerte.

+1

Esta expresión regular funciona parcialmente, no resuelve las entradas en blanco secuenciales, por ejemplo ,,,, será, \ n ,, \ n, deberían ser utilizables si se ejecuta dos veces – ievgen

+0

resumirá la respuesta y comentario anterior. Lo siguiente funcionó para mí, en el orden: sed -i 's/,, /, \ N/g' $ archivo, sed -i 's/,, /,' g '$ file, sed -i' s/\ N, $/\ N/g '$ file, –

95

MySQL manual dice:

Al leer los datos con LOAD DATA INFILE , vacío o columnas que faltan son actualizado con ''. Si desea un valor NULO en una columna, debe usar \ N en el archivo de datos. La palabra literal "NULO" también se puede utilizar en algunas circunstancias .

por lo que necesita para reemplazar los espacios en blanco con \ N así:

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

Gracias por la sugerencia: soy escéptico para editar los datos de fuente sin procesar, pero si esta es la única forma de hacerlo lo probaré. – Spiros

+7

Entiendo tu escepticismo, a nadie le gusta editar datos sin procesar, simplemente no se siente bien. Sin embargo, si lo piensa por un minuto, tiene que haber una manera de distinguir entre NULL y cadena vacía. Si las entradas en blanco se traducen a NULLs, necesitaría una secuencia especial para la cadena vacía. Sería bueno tener una forma de decirle a MySQL cómo tratar las entradas en blanco, algo así como LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE moo TRATAR EN BLANCO COMO NULO ... – Janci

+2

OK, pero si tiene 'Campos Encerrado por: "' es ese '" \ N "' de '" nombre ", \ N," cosas "' – Jonathon

5

El comportamiento es diferente dependiendo de la configuración de la base de datos. En el modo estricto esto arrojaría un error si no una advertencia. La siguiente consulta se puede usar para identificar la configuración de la base de datos.

mysql> show variables like 'sql_mode'; 
+0

¡Gracias! Me estaba rascando la cabeza tratando de averiguar por qué la importación de un archivo CSV con columnas vacías que había importado con éxito en el servidor de producción ayer no funcionaba en mi flamante instalación local: ¡esta fue la respuesta en mi caso! –