MySQL carga valores NULL de datos CSV

167

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 están al final de la fila:

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

La siguiente tabla fue creada en MySQL:

+ ------- + -------- + ------ + ----- + --------- + ------- +
El | Campo | Tipo | Nulo | Clave | Predeterminado | Extra |
+ ------- + -------- + ------ + ----- + --------- + ------- +
El | uno | int (1) | SI | El | NULL | El |
El | dos | int (1) | SI | El | NULL | El |
El | tres | int (1) | SI | El | NULL | El |
El | cuatro | int (1) | SI | El | NULL | El |
El | cinco | int (1) | SI | El | NULL | El |
+ ------- + -------- + ------ + ----- + --------- + ------- +

Estoy tratando de cargar los datos usando el comando MySQL LOAD:

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

La tabla resultante:

+ ------ + ------ + ------- + ------ + ------ +
El | uno | dos | tres | cuatro | cinco |
+ ------ + ------ + ------- + ------ + ------ +
El | 1 | 2 | 3 | 4 | 5 |
El | 1 | 2 | 3 | 0 | 5 |
El | 1 | 2 | 3 | NULL | NULL |
+ ------ + ------ + ------- + ------ + ------ +

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

Desafortunadamente, tengo que poder distinguir entre NULL y 0 en esta etapa para que cualquier ayuda sea apreciada.

Gracias S.

editar

La salida de SHOW WARNINGS:

+ --------- + ------ + -------------------------------- ------------------------ +
El | Nivel | Código | Mensaje |
+ --------- + ------ + -------------------------------- ------------------------ +
El | Advertencia | 1366 Valor entero incorrecto: '' para la columna 'cuatro' en la fila 2 |
El | Advertencia | 1261 La fila 3 no contiene datos para todas las columnas |
El | Advertencia | 1261 La fila 3 no contiene datos para todas las columnas |
+ --------- + ------ + -------------------------------- ------------------------ +
Spiros
fuente
Con cambios en el esquema de datos como ese, usaría d6tstack que alinea todas las columnas antes de ejecutar LOAD DATA. Consulte la sección de ejemplos d6tstack SQL sobre cambios en el esquema de datos.
citynorman

Respuestas:

193

Esto hará lo que quieras. Lee el cuarto campo en una variable local y luego establece el valor del campo real en NULL, si la variable local termina conteniendo 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 están posiblemente vacíos, los leería todos en variables y tendría varias instrucciones 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,'')
;
Duncan Lock
fuente
Teóricamente, supongo, pero todo está 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.
Duncan Lock
44
Realmente me gusta esta respuesta. Los usuarios pueden ver cadenas vacías ''cuando descargan un csv (usando IFNULL(Col,'')en la SELECT INTO OUTFILEconsulta) para Excel, pero luego las suben y las aceptan como nulas frente a tener que lidiar \Nen el csv. ¡Gracias!
Chris
9
para las fechas usé 'NULLIF (STR_TO_DATE (@ date1, "% d /% m /% Y"), "0000-00-00")'
Joaquín L. Robles
1
Tengo un archivo csv que contiene ceros 0que deberían convertirse NULL(porque no es posible tener un valor cero para los datos en cuestión) y también cadenas vacías. ¿Cómo asegurarse de que tanto los ceros como las cadenas vacías se convierten NULL?
Paul Rougieux
Si los valores cero y cadenas vacías están en columnas separadas, a continuación, sólo hacer lo anterior para las cadenas vacías, y algo como esto para los ceros: nullif(@vone, 0).
Duncan Lock
136

El manual de MySQL dice:

Al leer datos con LOAD DATA INFILE, las columnas vacías o faltantes se actualizan con ''. Si desea un valor NULL en una columna, debe usar \ N en el archivo de datos. La palabra literal "NULL" también puede usarse en algunas circunstancias.

Por lo tanto, debe reemplazar los espacios en blanco con \ N de esta manera:

1,2,3,4,5
1,2,3,\N,5
1,2,3
Janci
fuente
3
Gracias por el consejo: soy escéptico para editar los datos de origen sin procesar, pero si esta es la única forma de evitarlo, lo probaré.
Spiros
77
Entiendo su escepticismo, a nadie le gusta editar datos en bruto, 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 NULL, necesitará una secuencia especial para la cadena vacía. Sin embargo, sería bueno tener una manera de decirle a MySQL cómo tratar las entradas en blanco, algo así como LOAD DATA INFILE '/tmp/testdata.txt' EN LA TABLA moo TRATAR EN BLANCO COMO NULO ...
Janci
2
OK, pero si usted tiene Fields enclosed by: "es que "\N"de"name",\N,"stuff"
Jonathon
3
Puedo verificar que al menos para "phpMyAdmin 3.5.5" no \Nse acepta ningún estilo de denotar NULL. En su lugar NULL, use , como en este ejemplo:"name","age",NULL,"other","stuff"
Jonathon
1
Tenemos MySQL 5.5.46-0 + deb8u1. Intenté NULL y \ N, y solo \ N funcionó para nosotros.
raphael75
6

El comportamiento es diferente según la configuración de la base de datos. En el modo estricto, esto arrojaría un error o una advertencia. La siguiente consulta puede usarse para identificar la configuración de la base de datos.

mysql> show variables like 'sql_mode';
Dobi
fuente
¡Gracias! Me estaba rascando la cabeza tratando de averiguar por qué importar un CSV con columnas vacías que había importado con éxito en el servidor de producción ayer no funcionaba en mi nueva instalación local: ¡esta fue la respuesta en mi caso!
Emma Burrows
3

Preprocese su entrada CSV para reemplazar las entradas en blanco con \ N.

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

Buena suerte.

Sam Goldman
fuente
1
Esta expresión regular funciona parcialmente, no resuelve entradas secuenciales en blanco, por ejemplo ,,,, será, \ n ,, \ n, debería ser utilizable si la ejecuta dos veces
decir, el
1
Resumirá la respuesta y el comentario anterior. Lo siguiente funcionó para mí, en el orden: sed -i 's / ,, /, \ N / g' $ file, sed -i 's / ,, /, / g' $ file, sed -i 's / \ N, $ / \ N / g '$ archivo,
Omar Khazamov
Me gustaría hacer esto, pero no tengo claro cómo está ejecutando esta expresión regular. Si está utilizando MySQL para ejecutar esto contra el archivo, esta sería la mejor solución. Pero no lo dices y no quiero pasar mucho tiempo buscando en Google cómo hacer algo que puede no ser posible.
DonkeyKong
1

(variable1, @ variable2, ..) SET variable2 = nullif (@ variable2, '' o '') >> puede poner cualquier condición

Dijo
fuente
0

mostrar variables

Show variables like "`secure_file_priv`";

Nota: mantenga su archivo csv en la ubicación dada por el comando anterior.

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

Nota: aquí la datecolumna ' ' tiene algunos valores en blanco en el archivo 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);
Nirmal Silwal
fuente