Menu

Importare un CSV in SQLite: caricare dati con .import e --csv

Come importare file CSV in SQLite con il comando .import: gestire le intestazioni, le tabelle esistenti, i separatori personalizzati e gli errori più comuni.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

L'importazione CSV sta nella CLI, non nell'SQL

Nel dialetto SQL di SQLite non esiste un'istruzione IMPORT. Il caricamento dei CSV è una funzionalità della shell da riga di comando sqlite3: un dot-command chiamato .import. È un cambio di prospettiva importante se arrivi da LOAD DATA INFILE di MySQL o da COPY di Postgres: quelli girano sul server, mentre .import è qualcosa che fa per te lo strumento client, leggendo il file ed eseguendo istruzioni INSERT dietro le quinte.

Quindi tutto quello che vedi in questa pagina presuppone che tu sia dentro la shell sqlite3:

sqlite3 mydata.db

Se invece devi importare dal codice di un'applicazione (Python, Node, Go), leggerai il CSV nel tuo linguaggio e userai istruzioni INSERT parametrizzate. Vedremo questo approccio nel capitolo sull'integrazione con le applicazioni. Qui ci concentriamo sulla CLI.

Il .import di base

La strada più breve: dici a SQLite che il file è un CSV, poi punti .import sul file e su un nome di tabella.

.mode csv
.import people.csv people

Succedono due cose diverse a seconda che people esista già o no:

  • La tabella non esiste: SQLite la crea, usando la prima riga del CSV come nomi delle colonne. Ogni colonna ha affinità TEXT.
  • La tabella esiste: SQLite inserisce ogni riga del file come dato. L'eventuale riga di intestazione diventa una riga.

È nel secondo caso che quasi tutti cadono al primo tentativo. Se il tuo CSV ha un'intestazione e la tabella esiste già, devi saltarla in modo esplicito.

Saltare l'intestazione su una tabella esistente

Usa --skip 1 per dire a .import di ignorare le prime N righe:

CREATE TABLE people (
    name TEXT,
    age  INTEGER,
    city TEXT
);

.import --csv --skip 1 people.csv people

--csv è una scorciatoia per .mode csv limitata a questo solo comando, quindi non devi impostare la modalità a parte. --skip 1 scarta l'intestazione. Le righe restanti vengono inserite in people nell'ordine delle colonne.

Un controllo veloce dopo l'importazione:

SELECT count(*) FROM people;
SELECT * FROM people LIMIT 5;

L'ordine delle colonne nel file deve corrispondere all'ordine delle colonne nella tabella. Non c'è una mappatura basata sull'intestazione: .import si limita ad allineare l'N-esimo campo con l'N-esima colonna.

Lasciare che SQLite crei la tabella per te

Per il lavoro esplorativo, la strada più semplice è saltare del tutto CREATE TABLE e lasciare che .import costruisca la tabella dall'intestazione:

.mode csv
.import sales.csv sales

.schema sales

.schema sales mostrerà qualcosa del genere:

CREATE TABLE sales(
  "order_id" TEXT,
  "amount" TEXT,
  "ordered_at" TEXT
);

Nota che ogni colonna è TEXT. È voluto: .import non prova a dedurre i tipi. Se vuoi amount come numero reale e ordered_at come timestamp vero e proprio, crea prima tu la tabella con i tipi giusti, poi importa con --skip 1. L'affinità di tipo di SQLite convertirà le stringhe numeriche in interi e reali all'inserimento.

Separatori personalizzati: TSV, pipe, punto e virgola

.mode csv usa la virgola. Per i file separati da tabulazioni, cambia modalità:

.mode tabs
.import data.tsv events

Per altri separatori, usa .separator dopo aver scelto una modalità:

.mode csv
.separator "|"
.import pipe_data.txt events

Una cosa da sapere: .mode csv segue le regole di quoting della RFC 4180, quindi i campi con virgole o a capo interni funzionano purché siano correttamente racchiusi tra ". .mode tabs è una modalità più semplice che divide su un carattere, senza quoting. Se il tuo file ha campi tra virgolette con separatori interni, resta in .mode csv e cambia il separatore. È il caso tipico dei CSV esportati da Excel con impostazioni italiane, che usano il punto e virgola.

Un esempio realistico

Supponiamo che orders.csv sia così:

order_id,customer,amount,ordered_at
1001,Ada,49.99,2026-01-12
1002,Boris,12.50,2026-01-13
1003,"Chen, Wei",199.00,2026-01-14

Nota che la riga 3 ha una virgola dentro un campo tra virgolette. Ecco la sessione completa:

In una shell vera, il blocco INSERT sarebbe sostituito da un unico .import --csv --skip 1 orders.csv orders. Il campo "Chen, Wei" resta intatto perché la modalità CSV rispetta le virgolette. Grazie ai tipi delle colonne, amount diventa un numero reale e order_id un intero.

Racchiudere l'importazione in una transazione

.import esegue un INSERT per riga. Per qualche migliaio di righe va bene. Per un milione è lentissimo, a meno che tu non racchiuda tutto in una transazione, così SQLite non fa un commit dopo ogni riga:

BEGIN;
.import --csv --skip 1 big_file.csv events
COMMIT;

Questa sola modifica può trasformare un'importazione di diversi minuti in pochi secondi. Se qualcosa fallisce a metà, ROLLBACK annulla il caricamento parziale, il che è comodo anche per riprovare.

Puoi accelerare ancora eliminando gli indici prima dell'importazione e ricreandoli dopo: la manutenzione degli indici riga per riga si fa sentire.

Errori comuni e come risolverli

Error: expected N columns but found M: il numero di campi di una riga non corrisponde alla tabella. Di solito:

  • Una virgola di troppo in un campo senza virgolette. Riesporta con un quoting CSV corretto, oppure passa a .mode csv (RFC 4180) invece di .mode tabs.
  • Una riga vuota alla fine del file. Modifica il file o usa --skip in modo creativo.
  • La tabella ha più colonne del CSV. Aggiungi le colonne mancanti al file, oppure inserisci in una tabella di appoggio con la forma giusta e copia nella tabella vera.

L'intestazione compare come dato: hai dimenticato --skip 1 su una tabella esistente. Elimina quella riga (DELETE FROM t WHERE rowid = 1) e riesegui con il flag.

Numeri salvati come stringhe: hai lasciato che .import creasse la tabella, quindi ogni colonna è TEXT. Elimina la tabella, definiscila in modo esplicito con colonne INTEGER/REAL e reimporta.

Error: no such file: il percorso è relativo alla cartella da cui hai avviato sqlite3, non al file del database. Usa un percorso assoluto oppure fai cd nella cartella giusta prima di aprire la shell.

La CLI stampa i numeri di riga negli errori, ed è il modo più rapido per trovare la riga incriminata in un file grande.

Riepilogo veloce

  • .import è un dot-command della CLI, non SQL. Eseguilo dentro la shell sqlite3.
  • Usa --csv per gestire correttamente le virgolette e --skip 1 per ignorare una riga di intestazione.
  • Se la tabella non esiste, .import la crea dall'intestazione, ma ogni colonna sarà TEXT. Crea tu la tabella per avere i tipi giusti.
  • Racchiudi le importazioni grandi in BEGIN/COMMIT per evitare una transazione per riga.
  • L'ordine delle colonne nel file deve corrispondere all'ordine delle colonne nella tabella.

Prossimo passo: esportare i dati

Importare è metà del lavoro. La stessa shell può riversare risultati di query o tabelle intere in CSV, JSON o SQL: utile per backup, pipeline di dati e per passare i dati ad altri strumenti. Lo vediamo nella pagina sull'esportazione dei dati.

Domande frequenti

Come importo un file CSV in SQLite?

Apri il database con la CLI sqlite3, passa alla modalità CSV con .mode csv, poi esegui .import data.csv table_name. Se la tabella non esiste ancora, SQLite la crea usando la prima riga del file come nomi delle colonne. Se esiste già, ogni riga del file viene inserita come dato, quindi di solito ti serve .import --skip 1 per saltare l'intestazione.

Come importo un CSV con intestazione in una tabella SQLite esistente?

Usa .import --csv --skip 1 data.csv table_name. Il flag --skip 1 dice a SQLite di ignorare la prima riga, così l'intestazione non diventa una riga di dati. Senza, ti ritroverai con una riga che contiene letteralmente i nomi delle colonne.

Perché l'importazione CSV in SQLite fallisce con 'expected N columns but found M'?

Il file ha righe con un numero di colonne diverso da quello della tabella, di solito per via di virgole interne, virgolette non gestite o una riga vuota finale. Usa .mode csv (o --csv) invece di .mode tabs, così SQLite gestisce le virgolette secondo la RFC 4180, e controlla il file con un editor di testo per trovare separatori fuori posto. La CLI stampa il numero della riga incriminata, che è il modo più rapido per trovarla.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA