Pourquoi les tables STRICT existent
SQLite, par défaut, est très permissif avec les types. Déclarez une colonne en INTEGER, insérez la chaîne "hello" : SQLite hausse les épaules et stocke la chaîne sans broncher. Cette souplesse était un choix de conception assumé dans les années 90, mais elle déroute les développeurs venant de Postgres ou MySQL — et surtout, elle masque des bugs.
Les tables STRICT, introduites dans SQLite 3.37, corrigent ce comportement. Vous activez le mode strict table par table, et à partir de là, les types de colonnes veulent vraiment dire ce qu'ils annoncent.
Le mot-clé STRICT se place juste après la parenthèse fermante. Tout le reste ressemble à un CREATE TABLE classique. La différence saute aux yeux dès que vous tentez d'insérer une valeur du mauvais type dans une colonne.
Ce que le mode STRICT impose vraiment
Dans une table classique, l'affinité de type tente de convertir la valeur vers le type déclaré, et si ça échoue, elle la stocke telle quelle. Dans une table STRICT, le moindre écart de type déclenche une erreur.
Faites le même essai sur une table non‑STRICT et la troisième insertion passe sans broncher : SQLite range tranquillement la chaîne 'oops' dans une colonne que vous aviez pourtant déclarée INTEGER. Quelques mois plus tard, une requête d'agrégation vous sort un résultat aberrant et vous y passez l'après‑midi pour comprendre d'où ça vient. Avec le mode STRICT, l'erreur saute aux yeux dès l'insertion, là où vous pouvez encore la corriger.
Voici l'erreur que vous obtiendrez :
Runtime error: cannot store TEXT value in INTEGER column accounts.balance
Clair, direct, impossible à louper.
Les cinq types autorisés
Une table STRICT n'accepte que cinq noms de types :
INTEGER— nombres entiers.REAL— nombres à virgule flottante.TEXT— chaînes de caractères.BLOB— octets bruts.ANY— n'importe quel type, sans conversion.
Et c'est tout. Les alias laxistes que SQLite tolère habituellement — VARCHAR(255), DOUBLE, BOOLEAN, DATETIME, INT — déclenchent tous une erreur dans une table STRICT :
The error:
Erreur d'analyse : type de données inconnu pour bad.name : "VARCHAR(255)"
La solution, c'est d'utiliser l'un des cinq noms canoniques. VARCHAR(255) devient TEXT, DATETIME devient TEXT aussi (de toute façon, SQLite stocke les dates sous forme de chaînes ISO), et BOOLEAN devient INTEGER (avec 0 et 1).
La porte de sortie : la colonne ANY
ANY est le seul type qui autorise une colonne STRICT à contenir des valeurs hétérogènes. Pratique, par exemple, pour une colonne value générique dans une table clé/valeur :
ANY est un cas particulier dans les tables STRICT : les valeurs y sont stockées sans la coercition de type que ce même mot-clé déclencherait ailleurs. Une chaîne '100' reste une chaîne, et un entier 100 reste un entier. Les appels à typeof() dans la requête précédente le confirment.
Dans une table non-STRICT, une colonne d'affinité ANY convertirait les chaînes ressemblant à des nombres en nombres. Le mode STRICT, lui, conserve le type d'origine à l'identique.
STRICT et PRIMARY KEY
Voici une subtilité à connaître : dans une table classique, INTEGER PRIMARY KEY a un statut particulier — il devient un alias de rowid et n'accepte que des entiers. Les autres déclarations de clé primaire sont nettement plus permissives.
Dans une table STRICT, le type de la colonne est appliqué qu'il s'agisse ou non de la clé primaire :
Le second INSERT échoue. Dans une table non-STRICT, la valeur 42 aurait été stockée silencieusement dans la colonne TEXT qui sert de clé primaire. Ici, SQLite te le signale clairement.
Mélanger des tables STRICT et non-STRICT
Le mode STRICT s'applique table par table, pas à toute la base. Rien ne t'empêche d'avoir une table users en mode strict et une table events plus permissive dans le même fichier. Les clés étrangères fonctionnent entre les deux exactement comme d'habitude.
La table events n'a pas de STRICT ni de type déclaré sur payload, donc elle accepte n'importe quoi. Pratique parfois, risqué par défaut. Réservez le stockage sans typage aux cas où vous avez réellement besoin d'une colonne fourre-tout.
Quand utiliser le mode STRICT
Pour un nouveau schéma, la réponse est « presque toujours ». Le coût est minime : un mot-clé par table, plus le fait de retenir les cinq noms de types canoniques. En contrepartie, les bugs qui se glisseraient normalement dans vos données apparaissent dès l'INSERT fautif.
Vous pouvez vous passer de STRICT dans ces cas :
- Vous maintenez une vieille base SQLite dont le schéma repose sur le typage souple.
- Vous visez une version de SQLite antérieure à 3.37 (octobre 2021) — le mot-clé n'existe pas.
- Vous voulez vraiment qu'une colonne accueille des types mixtes ; et même là, mieux vaut une table
STRICTavec une colonneANYqu'une table non-STRICT, parce que tout le reste reste contrôlé.
Une petite checklist pour convertir une table classique en STRICT :
- Remplacez
VARCHAR,CHAR,NVARCHARparTEXT. - Remplacez
DOUBLE,FLOAT,NUMERICparREAL. - Remplacez
BOOLEAN,BIT,TINYINTparINTEGER. - Remplacez
DATETIME,TIMESTAMP,DATEparTEXT(ouINTEGERsi vous stockez des timestamps unix). - Ajoutez
STRICTaprès la parenthèse fermante.
La suite : les clés primaires
Les tables STRICT verrouillent la façon dont les colonnes stockent leurs données. La prochaine chose à verrouiller, c'est quelle colonne identifie chaque ligne — et les clés primaires de SQLite ont quelques particularités (notamment autour d'INTEGER PRIMARY KEY et de rowid) qu'il vaut mieux connaître avant de concevoir un vrai schéma.
Questions fréquentes
Qu'est-ce qu'une table STRICT en SQLite ?
Une table STRICT impose le type déclaré de chaque colonne : si vous indiquez INTEGER, SQLite refusera toute valeur qui n'est pas un entier ou NULL. Pour l'activer, il suffit d'ajouter le mot-clé STRICT après la parenthèse fermante du CREATE TABLE. Sans ça, SQLite applique son système d'affinité de type, qui convertit la valeur quand il peut et la stocke telle quelle quand il ne peut pas.
Quels types puis-je utiliser dans une table STRICT ?
Cinq, et pas un de plus : INTEGER, REAL, TEXT, BLOB et ANY. Tous les alias acceptés dans les tables classiques — VARCHAR, DOUBLE, BOOLEAN, DATETIME — déclenchent une erreur dans une table STRICT. La colonne ANY sert de porte de sortie : elle accepte n'importe quel type sans tenter de conversion.
Faut-il utiliser des tables STRICT pour les nouvelles bases SQLite ?
Pour la plupart des nouveaux schémas, oui. Les tables STRICT attrapent des bugs que les tables classiques avalent en silence : une chaîne qui se glisse dans une colonne INTEGER, une liste sérialisée par accident dans un REAL. Le coût ? Un mot-clé en plus par table et l'abandon des noms de types exotiques. Disponible depuis SQLite 3.37 (2021).