Menu

Importer un CSV dans SQLite avec .import

Comment charger un fichier CSV dans SQLite avec la commande .import : gestion des en-têtes, tables existantes, séparateurs personnalisés et erreurs courantes.

Cette page contient des éditeurs exécutables — modifiez, exécutez et voyez la sortie instantanément.

L'import CSV se passe dans le CLI, pas en SQL

Le dialecte SQL de SQLite ne propose aucune instruction IMPORT. Le chargement de fichiers CSV est en réalité une fonctionnalité du shell en ligne de commande sqlite3 — une commande pointée nommée .import. C'est un changement de logique à intégrer si vous arrivez de LOAD DATA INFILE (MySQL) ou de COPY (Postgres) : ces commandes-là s'exécutent côté serveur, alors que .import est exécutée par l'outil client, qui lit le fichier et déclenche les INSERT correspondants en coulisses.

Tout ce qui suit part donc du principe que vous êtes dans le shell sqlite3 :

sqlite3 mydata.db

Si vous devez plutôt faire l'import depuis du code applicatif — Python, Node, Go — vous lirez le CSV dans votre langage avant d'utiliser des requêtes INSERT paramétrées. On verra cette approche dans le chapitre dédié à l'intégration applicative. Ici, on se concentre sur la ligne de commande.

La commande .import en bref

Le plus court chemin pour importer un CSV dans SQLite : indiquer que le fichier est au format CSV, puis passer à .import le chemin du fichier ainsi que le nom de la table.

.mode csv
.import people.csv people

Selon que people existe déjà ou non, deux scénarios sont possibles :

  • La table n'existe pas — SQLite la crée en utilisant la première ligne du CSV comme noms de colonnes. Toutes les colonnes héritent de l'affinité TEXT.
  • La table existe déjà — SQLite insère toutes les lignes du fichier comme données. La ligne d'en-tête, si elle est présente, devient une ligne de la table.

C'est ce deuxième cas qui piège la plupart des gens au premier essai. Si votre CSV contient un en-tête et que la table existe déjà, vous devez explicitement sauter cette première ligne.

Ignorer l'en-tête lors d'un import dans une table existante

Utilisez --skip 1 pour indiquer à .import d'ignorer les N premières lignes :

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

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

--csv est un raccourci équivalent à .mode csv mais limité à cette seule commande, ce qui évite d'avoir à changer le mode au préalable. L'option --skip 1 permet d'ignorer la ligne d'en-tête. Les lignes restantes sont ensuite insérées dans people en respectant l'ordre des colonnes.

Une petite vérification après l'import :

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

L'ordre des colonnes dans le fichier doit correspondre à celui de la table. Aucun mappage par en-tête n'est effectué — .import se contente d'aligner le Nième champ avec la Nième colonne.

Laisser SQLite créer la table à votre place

Pour du travail exploratoire, le plus simple est de zapper le CREATE TABLE et de laisser .import générer la table à partir de l'en-tête du fichier CSV :

.mode csv
.import sales.csv sales

.schema sales

.schema sales va afficher quelque chose comme :

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

Notez que toutes les colonnes sont en TEXT. C'est voulu : .import ne cherche pas à deviner les types. Si vous voulez amount en nombre réel et ordered_at en vrai timestamp, créez d'abord la table vous-même avec les bons types, puis lancez l'import avec --skip 1. Grâce à l'affinité de type de SQLite, les chaînes numériques seront converties en entiers et en réels au moment de l'insertion.

Séparateurs personnalisés : TSV, pipe, point-virgule

.mode csv part du principe que le séparateur est la virgule. Pour les fichiers séparés par des tabulations, changez de mode :

.mode tabs
.import data.tsv events

Pour utiliser d'autres séparateurs, lance .separator après avoir choisi un mode :

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

Bon à savoir : .mode csv respecte les règles de citation du RFC 4180 — les champs contenant des virgules ou des sauts de ligne fonctionnent sans souci, à condition d'être correctement entourés de ". .mode tabs, lui, est un mode plus rudimentaire : il découpe sur un caractère, sans gestion des guillemets. Si votre fichier contient des champs entre guillemets avec des séparateurs à l'intérieur, restez en .mode csv et changez plutôt le séparateur.

Cas concret : importer un CSV dans SQLite pas à pas

Imaginons que orders.csv ressemble à ceci :

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

Notez que la ligne 3 contient une virgule à l'intérieur d'un champ entre guillemets. Voici la session complète :

Dans un vrai shell, le bloc INSERT serait remplacé par un seul .import --csv --skip 1 orders.csv orders. Le champ "Chen, Wei" reste intact, car le mode CSV respecte les guillemets. amount se retrouve bien stocké comme nombre réel et order_id comme entier, grâce aux types des colonnes.

Encapsuler l'import dans une transaction

.import exécute un INSERT par ligne. Pour quelques milliers de lignes, ça passe sans souci. Mais sur un million de lignes, ça devient atrocement lent — sauf si on enveloppe l'ensemble dans une transaction, pour éviter que SQLite ne commite après chaque ligne :

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

Ce simple changement peut transformer une importation de plusieurs minutes en quelques secondes. Si quelque chose plante en cours de route, ROLLBACK annule le chargement partiel — pratique aussi quand on veut réessayer.

Pour aller encore plus vite, vous pouvez supprimer les index avant l'import et les recréer après. La maintenance des index ligne par ligne, ça finit par coûter cher.

Erreurs courantes et comment les corriger

Error: expected N columns but found M — le nombre de champs d'une ligne ne correspond pas à la table. En général :

  • Une virgule baladeuse dans un champ non protégé par des guillemets. Réexportez avec un échappement CSV correct, ou passez en .mode csv (RFC 4180) au lieu de .mode tabs.
  • Une ligne vide en fin de fichier. Éditez le fichier ou jouez avec --skip.
  • La table a plus de colonnes que le CSV. Soit vous ajoutez les colonnes manquantes au fichier, soit vous importez d'abord dans une table tampon ayant la bonne forme, puis vous recopiez vers la vraie table.

La ligne d'en-tête apparaît comme une donnée — vous avez oublié --skip 1 sur une table existante. Supprimez la ligne fautive (DELETE FROM t WHERE rowid = 1) et relancez avec l'option.

Des nombres stockés en chaînes — vous avez laissé .import créer la table tout seul, donc toutes les colonnes sont en TEXT. Supprimez la table, redéfinissez-la explicitement avec des colonnes INTEGER/REAL, et réimportez.

Error: no such file — le chemin est relatif au dossier depuis lequel vous avez lancé sqlite3, pas à l'emplacement du fichier de base. Utilisez un chemin absolu ou faites cd vers le bon dossier avant d'ouvrir le shell.

La CLI affiche le numéro de ligne en cas d'erreur, c'est le moyen le plus rapide de retrouver la ligne fautive dans un gros fichier.

Récapitulatif express

  • .import est une commande dot de la CLI, pas du SQL. Elle s'utilise dans le shell sqlite3.
  • Utilisez --csv pour gérer correctement les guillemets, et --skip 1 pour ignorer la ligne d'en-tête.
  • Si la table n'existe pas, .import la crée à partir de l'en-tête — mais toutes les colonnes seront en TEXT. Créez la table vous-même pour avoir les bons types.
  • Encadrez les gros imports avec BEGIN/COMMIT pour éviter une transaction par ligne.
  • L'ordre des colonnes dans le fichier doit correspondre à l'ordre des colonnes dans la table.

La suite : exporter les données

L'import, ce n'est que la moitié du chemin. Le même shell sait renvoyer les résultats d'une requête ou des tables entières vers du CSV, du JSON ou du SQL — pratique pour les sauvegardes, les pipelines de données ou pour transmettre des données à d'autres outils. On voit ça dans le chapitre sur l'export.

Questions fréquentes

Comment importer un fichier CSV dans SQLite ?

Ouvrez la base avec le CLI sqlite3, passez en mode CSV avec .mode csv, puis lancez .import data.csv nom_table. Si la table n'existe pas encore, SQLite la crée en utilisant la première ligne du fichier comme noms de colonnes. Si elle existe déjà, toutes les lignes du fichier sont insérées comme données — du coup vous voudrez généralement utiliser .import --skip 1 pour ignorer l'en-tête.

Comment importer un CSV avec une ligne d'en-tête dans une table SQLite existante ?

Utilisez .import --csv --skip 1 data.csv nom_table. L'option --skip 1 indique à SQLite d'ignorer la première ligne pour éviter que l'en-tête se retrouve inséré comme une ligne de données. Sans ça, vous aurez une ligne contenant littéralement les noms de colonnes.

Pourquoi mon import CSV échoue avec 'expected N columns but found M' ?

Le fichier contient des lignes dont le nombre de colonnes ne correspond pas à la table — généralement à cause de virgules à l'intérieur d'un champ, de guillemets mal échappés ou d'une ligne vide en fin de fichier. Utilisez .mode csv (ou --csv) plutôt que .mode tabs pour que SQLite gère correctement les guillemets selon la RFC 4180, et inspectez le fichier dans un éditeur de texte pour repérer les séparateurs en trop. Le CLI affiche le numéro de la ligne fautive, c'est le moyen le plus rapide de retrouver le souci.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER