Da CSV a SQL, senza perdere gli zeri
Da un CSV esce lo script pronto da incollare: CREATE TABLE e INSERT per MySQL, PostgreSQL, SQLite o SQL Server. I tipi li decide il contenuto, i CAP tengono lo zero davanti e ogni colonna dice perché è diventata quello che è.
Quando serve, e perché conviene uno script
Il CSV arriva dal gestionale, da un modulo online o da un foglio di Google, e deve finire in un database. Le importazioni guidate decidono i tipi da sole e quando sbagliano non lo dicono: te ne accorgi mesi dopo, quando un CAP ha perso lo zero.
Qui esce invece uno script SQL: un CREATE TABLE con i tipi già scelti e gli INSERT con tutte le righe. È testo che si legge prima di eseguirlo, si incolla in phpMyAdmin, DBeaver o psql e si riesegue uguale su un altro computer. E la tabella non esce dal tuo browser: nessun caricamento, nessun account.
Che cosa diventa numero e che cosa resta testo
È la lezione di Da CSV a Excel, e nel database pesa di più, perché lì un tipo sbagliato non si corregge con un clic: un CAP come «00185» in una colonna INTEGER diventa 185, e lo zero non torna. Per questo una colonna resta testo se ha zeri davanti, se sono interi di 15 cifre o più (una carta, un IMEI: sono codici), se c'è un + davanti a una fila di cifre (un telefono internazionale), se sembrano IBAN o codici fiscali, se c'è un valore già rovinato in notazione esponenziale come «1,2E+15», e se il nome della colonna dice CAP, codice, telefono o matricola e dentro ci sono solo cifre.
Il resto lo decide il contenuto: INTEGER se sono tutti interi, DECIMAL con le cifre giuste se ci sono decimali, BOOLEAN se ci sono solo sì e no, vero e falso, true e false. Il separatore dei decimali si conta nel file: «1.234,56» è italiano, «1,234.56» è inglese. Se nessun numero lo dice e «1.250» si legge in due modi, decide il separatore delle colonne (con il punto e virgola i decimali hanno la virgola, con la virgola il punto), e la pagina lo scrive. I numeri arrivano nello SQL con le cifre del file, senza passare dalla virgola mobile.
Se scegli un tipo che un valore non regge, per esempio intero su una colonna con dentro «n.d.», la pagina dice quale valore e in quale riga, e lo SQL non lo scrive.
Le date, solo quando l'ordine è sicuro
«03/04/2024» è il 3 aprile per un italiano e il 4 marzo per un americano, e il file non lo dice. Per questo una colonna di date gg/mm/aaaa diventa DATE, riscritta anno-mese-giorno come la leggono tutti i database, solo se tutta la colonna è inequivocabile: almeno una data deve avere il giorno oltre il 12, e nessuna deve smentire l'ordine. Se no resta testo e la pagina lo dice; se l'ordine lo sai tu, lo scegli dal menu. Le date già scritte anno-mese-giorno passano sempre, quelle con l'anno a due cifre mai, perché «24» non dice il secolo.
SQLite non ha un vero tipo data: tiene la data come testo, e le sue funzioni capiscono solo la forma anno-mese-giorno, che è quella che esce da qui. SQL Server riceve DATE e non DATETIME, che legge la stessa scritta secondo la lingua della sessione.
Quattro database, quattro modi di scrivere la stessa riga
I nomi vanno fra virgolette doppie in SQLite e PostgreSQL, fra accenti gravi in MySQL, fra parentesi quadre in SQL Server, e l'apostrofo di «L'Aquila» si raddoppia dappertutto. In MySQL e MariaDB anche la barra rovesciata è un carattere speciale: scritto com'è, «C:\temp» diventa «C:», una tabulazione ed «emp». Qui la barra si raddoppia, lo script comincia con SET NAMES utf8mb4 perché il vecchio «utf8» rifiuta le emoji, e i testi diventano almeno VARCHAR(100): sotto i 64 caratteri InnoDB tiene la colonna dentro la riga, e con quaranta colonne così la riga supera gli 8.126 byte che regge.
SQL Server vuole la N davanti alle stringhe, se no le lettere fuori dalla sua codifica diventano punti interrogativi, usa BIT per sì e no (1 e 0, come SQLite) e accetta al massimo mille righe in un solo INSERT. Per questo le righe vanno a gruppi, cinquecento per istruzione se non scegli altro, e ogni INSERT resta sotto il megabyte, salvo una riga che da sola pesa di più. Gli INSERT stanno in una transazione, e in SQL Server con SET XACT_ABORT ON, senza il quale un errore annulla solo la sua istruzione: se l'esecuzione si ferma, non resta una tabella mezza piena. Il DROP TABLE IF EXISTS va solo insieme al CREATE TABLE, e in SQL Server esiste dalla versione 2016.
I nomi delle colonne diventano nomi veri
«Data di nascita», «Città» e «Prezzo (€)» diventano data_di_nascita, citta e prezzo: lettere senza accenti, cifre e trattini bassi, che si scrivono in una query senza virgolette. Una parola che il database tiene per sé, come order, group, user o key, riceve un trattino basso in fondo, se no la prima SELECT scritta a mano darebbe un errore incomprensibile. Due colonne con lo stesso nome diventano nome e nome_2, un nome che comincia con una cifra riceve «c_» davanti, e oltre i 63 caratteri, il limite di PostgreSQL, si accorcia. La corrispondenza è in vista, e ogni nome si riscrive a mano.
Celle vuote: NULL o testo vuoto
Per il database una cella vuota può essere due cose: NULL, l'assenza di un valore, o '', un testo lungo zero. COUNT(telefono) non conta i NULL, e WHERE telefono = '' non li trova. Per le colonne di testo scegli tu; in quelle di numeri, date e sì o no una cella vuota è sempre NULL, perché '' non è né un numero né una data. Lo stesso vale per una cella con scritto NULL, o \N come negli export di MySQL: lì non può voler dire altro. In una colonna di testo invece potrebbe essere la parola, e resta tale, fra apostrofi, a meno che tu non spunti la casella apposta.
Quello che non fa, detto chiaro
Non si collega a nessun database e non esegue niente: scrive lo script. Non crea chiavi primarie né indici, che dipendono da come userai la tabella. Un numero con il simbolo dell'euro o la percentuale resta testo, e così le date con l'ora; in SQLite anche i decimali oltre le 15 cifre, che la sua virgola mobile non conserva. Non legge i file di Excel: per quelli c'è prima Da Excel a CSV. Se il CSV è sporco, conviene sistemarlo prima con Pulisci un CSV. E se ti serve per un programma e non per un database, la strada giusta è CSV in JSON.
E per onestà: la prova di questo strumento esegue davvero lo script su SQLite, su PostgreSQL e su MariaDB, che qui si comporta come MySQL, e rilegge le righe dalla tabella. SQL Server qui non c'è: il suo script lo controlla un analizzatore scritto da altri, ma nessun SQL Server vero l'ha eseguito. E se sul tuo MySQL è acceso NO_BACKSLASH_ESCAPES, le barre rovesciate raddoppiate restano doppie.