De CSV a SQL, sin perder los ceros
De un CSV sale el script listo para pegar: CREATE TABLE e INSERT para MySQL, PostgreSQL, SQLite o SQL Server. Los tipos los decide el contenido, los códigos postales conservan el cero y cada columna dice por qué es lo que es.
Cuándo hace falta, y por qué conviene un script
El CSV sale del programa de gestión, de un formulario en línea o de una hoja de Google, y tiene que acabar en una base de datos. Los asistentes de importación deciden los tipos por su cuenta y cuando se equivocan no lo dicen: te das cuenta meses después, cuando un código postal ha perdido el cero.
Aquí sale en cambio un script SQL: un CREATE TABLE con los tipos ya elegidos y los INSERT con todas las filas. Es texto que se lee antes de ejecutarlo, se pega en phpMyAdmin, DBeaver o psql y se vuelve a ejecutar igual en otro ordenador. Y la tabla no sale de tu navegador: ninguna subida, ninguna cuenta.
Qué se convierte en número y qué se queda como texto
Es la lección de De CSV a Excel, y en la base de datos pesa más, porque allí un tipo equivocado no se arregla con un clic: un código postal como «00185» en una columna INTEGER se convierte en 185, y el cero ya no vuelve. Por eso una columna se queda como texto si tiene ceros delante, si son enteros de 15 cifras o más (una tarjeta, un IMEI: son códigos), si hay un + delante de una fila de cifras (un teléfono internacional), si parecen IBAN o códigos fiscales italianos, si hay un valor ya estropeado en notación científica como «1,2E+15», y si el nombre de la columna dice código postal, código, teléfono o matrícula y dentro solo hay cifras.
El resto lo decide el contenido: INTEGER si son todos enteros, DECIMAL con las cifras justas si hay decimales, BOOLEAN si solo hay sí y no, verdadero y falso, true y false. El separador de los decimales se cuenta en el archivo: «1.234,56» es continental, «1,234.56» es inglés. Si ningún número lo dice y «1.250» se lee de dos maneras, decide el separador de las columnas (con punto y coma los decimales llevan coma, con coma llevan punto), y la página lo escribe. Los números llegan al SQL con las cifras del archivo, sin pasar por la coma flotante.
Si eliges un tipo que un valor no aguanta, por ejemplo entero en una columna donde hay «n/d», la página dice qué valor y en qué fila, y el SQL no lo escribe.
Las fechas, solo cuando el orden es seguro
«03/04/2024» es el 3 de abril para un europeo y el 4 de marzo para un estadounidense, y el archivo no lo dice. Por eso una columna de fechas dd/mm/aaaa se convierte en DATE, reescrita año-mes-día como la leen todas las bases de datos, solo si toda la columna es inequívoca: al menos una fecha tiene que tener el día por encima de 12, y ninguna puede contradecir el orden. Si no, se queda como texto y la página lo dice; si el orden lo sabes tú, lo eliges en el menú. Las fechas ya escritas año-mes-día pasan siempre, las de año con dos cifras nunca, porque «24» no dice el siglo.
SQLite no tiene un tipo fecha de verdad: guarda la fecha como texto, y sus funciones solo entienden la forma año-mes-día, que es la que sale de aquí. SQL Server recibe DATE y no DATETIME, que lee el mismo texto según el idioma de la sesión.
Cuatro bases de datos, cuatro maneras de escribir la misma fila
Los nombres van entre comillas dobles en SQLite y PostgreSQL, entre acentos graves en MySQL, entre corchetes en SQL Server, y el apóstrofo de «O'Donnell» se duplica en todas partes. En MySQL y MariaDB también la barra invertida es un carácter especial: escrita tal cual, «C:\temp» se convierte en «C:», un tabulador y «emp». Aquí la barra se duplica, el script empieza con SET NAMES utf8mb4 porque el viejo «utf8» rechaza los emojis, y los textos pasan a ser al menos VARCHAR(100): por debajo de 64 caracteres InnoDB guarda la columna dentro de la fila, y con cuarenta columnas así la fila supera los 8.126 bytes que aguanta.
SQL Server quiere la N delante de las cadenas, si no las letras fuera de su codificación se convierten en signos de interrogación, usa BIT para sí y no (1 y 0, como SQLite) y acepta como mucho mil filas en un solo INSERT. Por eso las filas van en grupos, quinientas por instrucción si no eliges otra cosa, y cada INSERT se queda por debajo del megabyte, salvo una fila que por sí sola pesa más. Los INSERT van en una transacción, y en SQL Server con SET XACT_ABORT ON, sin el cual un error anula solo su instrucción: si la ejecución se para, no queda una tabla a medio llenar. El DROP TABLE IF EXISTS va solo junto al CREATE TABLE, y en SQL Server existe desde la versión 2016.
Los nombres de las columnas se convierten en nombres de verdad
«Fecha de nacimiento», «Città» y «Precio (€)» se convierten en fecha_de_nacimiento, citta y precio: letras sin acentos, cifras y guiones bajos, que se escriben en una query sin comillas. Una palabra reservada, como order, group, user o key, recibe un guion bajo al final, si no la primera SELECT escrita a mano daría un error incomprensible. Dos columnas con el mismo nombre pasan a ser nombre y nombre_2, un nombre que empieza por una cifra recibe «c_» delante, y más allá de 63 caracteres, el límite de PostgreSQL, se acorta. La correspondencia está a la vista, y cada nombre se reescribe a mano.
Celdas vacías: NULL o texto vacío
Para la base de datos una celda vacía puede ser dos cosas: NULL, la ausencia de un valor, o '', un texto de longitud cero. COUNT(telefono) no cuenta los NULL, y WHERE telefono = '' no los encuentra. En las columnas de texto eliges tú; en las de números, fechas y sí o no una celda vacía es siempre NULL, porque '' no es ni un número ni una fecha. Lo mismo vale para una celda con NULL escrito, o \N como en las exportaciones de MySQL: allí no puede querer decir otra cosa. En una columna de texto en cambio podría ser la palabra, y se queda así, entre apóstrofos, a menos que marques la casilla para ello.
Lo que no hace, dicho claro
No se conecta a ninguna base de datos y no ejecuta nada: escribe el script. No crea claves primarias ni índices, que dependen de cómo vayas a usar la tabla. Un número con el símbolo del euro o el signo de porcentaje se queda como texto, y lo mismo las fechas con hora; en SQLite también los decimales de más de 15 cifras, que su coma flotante no conserva. No lee los archivos de Excel: para esos está antes Excel (XLSX) a CSV. Si el CSV está sucio, conviene arreglarlo antes con Limpiar un CSV. Y si lo necesitas para un programa y no para una base de datos, el camino correcto es CSV a JSON.
Y por honestidad: la prueba de esta herramienta ejecuta de verdad el script en SQLite, en PostgreSQL y en MariaDB, que aquí se comporta como MySQL, y vuelve a leer las filas de la tabla. SQL Server aquí no está: su script lo revisa un analizador escrito por otros, pero ningún SQL Server de verdad lo ha ejecutado. Y si en tu MySQL está activado NO_BACKSLASH_ESCAPES, las barras invertidas duplicadas se quedan dobles.