Menu

Types de données SQLite : classes de stockage et typage dynamique

Comment SQLite stocke réellement les valeurs : les cinq classes de stockage, le principe du typage dynamique, et les pièges classiques quand on vient de Postgres ou MySQL.

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

Cinq classes de stockage, pas une myriade de types

En SQLite, chaque valeur est rangée dans l'une des cinq classes de stockage suivantes :

  • NULL — l'absence de valeur.
  • INTEGER — un entier signé, occupant de 1 à 8 octets selon sa taille.
  • REAL — un nombre à virgule flottante IEEE sur 8 octets.
  • TEXT — une chaîne de caractères, stockée dans l'encodage de la base (UTF-8 le plus souvent).
  • BLOB — des octets bruts, conservés tels quels.

Et c'est tout. Pas de BOOLEAN distinct, pas de DATETIME, pas de VARCHAR, pas de DECIMAL. Là où d'autres SGBD proposent des dizaines de types, SQLite n'en a que cinq — tout le reste se construit par-dessus.

typeof() renvoie la classe de stockage réelle de chaque valeur. Vous obtiendrez integer, real, text ou blob. Ces quatre-là — plus null — résument tout ce que SQLite sait manipuler.

Le typage dynamique de SQLite

Voici ce qui déstabilise souvent les développeurs venant de Postgres ou MySQL. Dans SQLite (sans le mode STRICT), le type déclaré sur une colonne tient davantage de la suggestion que d'un véritable contrat. Le type réel, lui, est rattaché à chaque valeur :

Les deux lignes ont été acceptées. La colonne id contient un entier dans une ligne et du texte dans l'autre ; body contient du texte puis un entier. SQLite stocke sans broncher des valeurs de n'importe quelle classe dans n'importe quelle colonne.

C'est ce qu'on appelle le typage dynamique de SQLite, et c'est un choix de conception assumé. Ça rend SQLite très permissif pour prototyper ou écrire des scripts vite faits. Mais ça veut aussi dire qu'une faute de frappe dans votre code applicatif peut stocker des données mal formées pendant des années sans que personne ne s'en aperçoive. Si ce compromis vous dérange — et pour la plupart des schémas en production, il devrait — les tables STRICT sont la solution. On y vient bientôt.

L'affinité de type en un paragraphe

Le type déclaré sur une colonne n'est pas ignoré pour autant : il donne à la colonne une affinité. Quand vous insérez une valeur, SQLite tente de la convertir vers l'affinité de la colonne si une conversion propre est possible. Une colonne TEXT qui reçoit le nombre 42 le conserve sous forme de texte '42' ; une colonne INTEGER qui reçoit la chaîne '42' le stocke en tant qu'entier 42. Si la conversion entraînait une perte d'information, le type d'origine est préservé.

Première ligne : l'entier 42 a été converti en texte '42', et la chaîne '100' est devenue l'entier 100. Deuxième ligne : '3.5' ne pouvait pas passer en INTEGER sans perte, donc la valeur est restée en texte. On reviendra sur l'affinité dans une page dédiée — pour l'instant, retenez simplement que le type de colonne influence quand même le stockage, même s'il ne l'impose pas.

Le type booléen en SQLite

Il n'existe pas de classe de stockage BOOLEAN en SQLite. Les booléens sont stockés sous forme d'entiers — 0 pour faux, 1 pour vrai :

Les mots-clés TRUE et FALSE sont reconnus (depuis SQLite 3.23) et correspondent à 1 et 0. Déclarer une colonne en BOOLEAN lui donne une affinité numérique, mais ne la limite pas à 0/1 : sans STRICT, rien ne vous empêche d'y insérer 'maybe', et SQLite ne bronchera pas.

Stocker une date dans SQLite

Pas de type DATETIME non plus. À vous de choisir l'un des trois formats de stockage ci-dessous — les fonctions de date de SQLite savent traiter les trois :

  • TEXT au format ISO-8601 : '2026-04-23 14:30:00'.
  • REAL sous forme de jour julien.
  • INTEGER en secondes depuis l'epoch Unix.

Le format texte ISO-8601 reste le choix le plus répandu : il se trie correctement comme une chaîne, il est lisible par un humain, et toutes les fonctions intégrées (date(), time(), datetime(), strftime(), julianday()) savent le digérer. Choisissez un seul format par colonne et tenez-vous-y ; mélanger plusieurs formats dans une même colonne, c'est typiquement le genre de truc qui vous retombe dessus six mois plus tard.

VARCHAR, CHAR et autres noms familiers

SQLite accepte tous les noms de types que vous connaissez d'autres bases de données — VARCHAR(255), CHAR(10), NVARCHAR, DECIMAL(10,2), DOUBLE, FLOAT, INT, BIGINT, MEDIUMINT. Ils passent tous sans problème au parsing. En coulisses, ils sont simplement ramenés à l'une des cinq classes de stockage via les règles d'affinité.

VARCHAR(255) n'impose aucune limite de 255 caractères : SQLite ignore tout simplement la longueur. De même, DECIMAL(10, 2) ne stocke pas un décimal à précision fixe — il reçoit l'affinité numérique et finit rangé comme INTEGER ou REAL. Ces noms n'existent que pour qu'un schéma copié depuis un autre SGBD passe sans erreur ; en revanche, ils ne traînent pas avec eux les contraintes qu'ils sous-entendent ailleurs.

Si vous avez besoin d'une arithmétique décimale exacte pour gérer de l'argent, stockez des centimes en INTEGER. Le REAL (virgule flottante) finira tôt ou tard par introduire des erreurs d'arrondi dès la troisième décimale.

NULL est une classe de stockage à part entière

NULL n'est pas qu'une simple « absence de valeur » — c'est une vraie valeur, avec sa propre classe de stockage, que typeof() renvoie tel quel :

b est signalé comme null. Et c'est important : NULL n'est égal à rien — pas même à un autre NULL. L'expression b = NULL n'est jamais vraie ; il faut écrire b IS NULL. On reviendra dessus en détail plus loin, dans la page sur les opérateurs et NULL, mais tout commence ici, au niveau de la classe de stockage.

Stocker des octets bruts avec BLOB

La classe BLOB stocke les octets tels quels, sans transformation — pratique pour des petites images, des hashs, des données encodées, bref tout ce qui n'est ni du texte ni un nombre :

Le littéral x'...' permet d'écrire des blobs en hexadécimal directement dans le SQL ; depuis votre code applicatif, vous passerez plutôt un tableau d'octets via un paramètre. À noter : length() appliqué à un blob renvoie le nombre d'octets, pas le nombre de caractères.

Petit conseil pratique : SQLite stocke sans broncher des blobs volumineux, mais ramener un blob de 50 Mo à chaque requête qui touche la ligne, c'est la lenteur assurée. Pour les gros fichiers, gardez le fichier sur disque et stockez juste le chemin en base.

Ce qu'il faut retenir

  • Cinq classes de stockage — NULL, INTEGER, REAL, TEXT, BLOB — couvrent absolument tout.
  • Les booléens sont des entiers ; les dates sont stockées en texte, en réel ou en entier (à vous de choisir).
  • Les types de colonnes déclarés sont des indications, pas des contrats (sauf si vous utilisez STRICT).
  • VARCHAR(255) et compagnie passent à l'analyse syntaxique, mais n'imposent ni la longueur ni la précision qu'ils suggèrent ailleurs.
  • typeof(value) est votre meilleur allié dès que vous avez un doute sur ce qui est réellement stocké.

Suite : l'affinité de type

Ce comportement « indicatif » qu'on a survolé suit en réalité des règles précises — cinq classes d'affinité, déduites du nom du type déclaré, appliquées à chaque insertion. C'est le sujet de la page suivante, et c'est la clé pour anticiper ce que SQLite va vraiment faire des valeurs que vous lui passez.

Questions fréquentes

Quels types de données SQLite gère-t-il ?

SQLite repose sur cinq classes de stockage : NULL, INTEGER, REAL, TEXT et BLOB. Toute valeur en base est rangée dans l'une d'entre elles. Les noms classiques comme VARCHAR(255), DATETIME ou BOOLEAN restent acceptés dans un CREATE TABLE — c'est purement pour la compatibilité — mais en interne ils sont ramenés à l'une des cinq classes au moment du stockage.

SQLite a-t-il un type booléen ou un type date/heure ?

Pas en tant que classes de stockage à part entière. Les booléens sont stockés en INTEGER (0 et 1), même si SQLite reconnaît aussi les mots-clés TRUE et FALSE. Pour les dates et heures, trois encodages sont possibles : TEXT (chaînes ISO-8601), REAL (jours juliens) ou INTEGER (secondes Unix epoch). Vous choisissez le format, et les fonctions de date fonctionnent indifféremment sur les trois.

Pourquoi parle-t-on de typage dynamique dans SQLite ?

Dans la plupart des SGBD, une colonne déclarée INTEGER refuse une chaîne. Dans SQLite, par défaut, le type déclaré est juste un indice : c'est chaque valeur qui porte son propre type, donc une colonne TEXT peut très bien contenir un entier si vous l'y insérez. Pratique parfois, casse-pied souvent. Les tables STRICT permettent de désactiver ce comportement.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER