Por qué existen las tablas STRICT
El comportamiento por defecto de SQLite con los tipos es famoso por lo permisivo que es. Declaras una columna como INTEGER, insertas la cadena "hello" y SQLite se encoge de hombros y guarda el texto tal cual. Esa flexibilidad fue una decisión de diseño intencionada en los 90, pero descoloca a quien viene de Postgres o MySQL... y, de paso, esconde bugs.
Las tablas STRICT, incorporadas en SQLite 3.37, vienen a corregir eso. Activas el modo strict tabla por tabla y, a partir de ahí, los tipos de las columnas significan exactamente lo que dicen.
La palabra clave STRICT se coloca después del paréntesis de cierre. Lo demás se ve como un CREATE TABLE cualquiera. La diferencia salta a la vista en cuanto intentas meter un valor del tipo equivocado en una columna.
Qué impone realmente STRICT
En una tabla normal, la afinidad de tipos de SQLite intenta convertir el valor al tipo declarado y, si no puede, lo guarda tal cual. En una tabla STRICT, esa discrepancia se convierte directamente en un error.
Si haces lo mismo contra una tabla sin STRICT, el tercer INSERT se cuela tan pancho — SQLite te guarda la cadena 'oops' en una columna que tú declaraste como INTEGER. Meses después, una consulta con agregaciones devuelve resultados sin sentido y te pasas la tarde investigando de dónde sale el problema. Con STRICT, el fallo salta en el momento del INSERT, justo donde puedes arreglarlo.
Este es el error que verás:
Error en tiempo de ejecución: no se puede almacenar un valor TEXT en la columna INTEGER accounts.balance
Claro, directo y difícil de pasar por alto.
Los cinco tipos permitidos
Las tablas STRICT solo aceptan cinco nombres de tipo:
INTEGER— números enteros.REAL— números de punto flotante.TEXT— cadenas de texto.BLOB— bytes en crudo.ANY— cualquier tipo, sin conversión.
Y ya. Los alias informales que SQLite suele aceptar sin chistar — VARCHAR(255), DOUBLE, BOOLEAN, DATETIME, INT — lanzan un error dentro de una tabla STRICT:
El error:
Error de análisis: tipo de dato desconocido para bad.name: "VARCHAR(255)"
La solución es usar uno de los cinco nombres canónicos. VARCHAR(255) pasa a ser TEXT, DATETIME también se convierte en TEXT (al fin y al cabo, SQLite guarda las fechas como cadenas ISO) y BOOLEAN se transforma en INTEGER (con 0 y 1).
La columna ANY: la vía de escape
ANY es el único tipo que permite que una columna STRICT almacene valores heterogéneos. Resulta muy útil, por ejemplo, para una columna value genérica dentro de una tabla clave/valor:
ANY se comporta de forma especial dentro de las tablas STRICT: guarda los valores sin aplicar la coerción de tipos que esa misma palabra implicaría en otros contextos. Un string '100' se queda como string; un entero 100 se queda como entero. Las llamadas a typeof() de la consulta anterior lo demuestran.
En una tabla no STRICT, una columna con afinidad ANY convertiría los strings que parecen números en números. STRICT, en cambio, conserva el tipo original tal cual.
STRICT y PRIMARY KEY
Hay una diferencia sutil: en una tabla normal, INTEGER PRIMARY KEY es un caso especial — se convierte en un alias de rowid y solo admite enteros. El resto de declaraciones de clave primaria son más permisivas.
En una tabla STRICT, el tipo de la columna se impone siempre, sea o no la clave primaria:
La segunda inserción falla. En una tabla sin STRICT, el valor 42 se guardaría silenciosamente en la columna de clave primaria de tipo TEXT. Acá, SQLite te avisa.
Combinar tablas STRICT y no STRICT
El modo STRICT se aplica por tabla, no a toda la base de datos. Podés tener una tabla users en modo strict y una tabla events relajada conviviendo en el mismo archivo. Las claves foráneas funcionan entre ambas igual que siempre.
La tabla events no tiene STRICT ni un tipo declarado en payload, así que acepta cualquier cosa que le metas. Útil de vez en cuando, pero arriesgado como opción por defecto. Reserva el almacenamiento sin tipos para casos donde de verdad necesites una columna comodín.
Cuándo usar STRICT
Para esquemas nuevos, la respuesta es "casi siempre". El coste es mínimo: una palabra clave por tabla y acordarte de los cinco nombres de tipo canónicos. La ventaja es que los bugs que normalmente se esconderían en tus datos saltan justo en el INSERT que los provocó.
Sáltate STRICT cuando:
- Mantienes una base de datos SQLite antigua cuyo esquema depende del tipado relajado.
- Tu objetivo es una versión de SQLite anterior a la 3.37 (octubre de 2021): ahí esa palabra clave no existe.
- Realmente quieres que una columna admita tipos mixtos. Incluso en ese caso, mejor una tabla
STRICTcon una columnaANYque una tabla sinSTRICT, porque todo lo demás sigue validado.
Una pequeña checklist para convertir una tabla normal en STRICT:
- Sustituye
VARCHAR,CHAR,NVARCHARporTEXT. - Sustituye
DOUBLE,FLOAT,NUMERICporREAL. - Sustituye
BOOLEAN,BIT,TINYINTporINTEGER. - Sustituye
DATETIME,TIMESTAMP,DATEporTEXT(oINTEGERsi guardas timestamps Unix). - Añade
STRICTdespués del paréntesis de cierre.
Lo que viene: claves primarias
Las tablas STRICT aprietan la forma en que las columnas guardan sus datos. Lo siguiente que conviene apretar es qué columna identifica cada fila. Y las claves primarias en SQLite tienen un par de rarezas (sobre todo con INTEGER PRIMARY KEY y rowid) que vale la pena conocer antes de diseñar un esquema de verdad.
Preguntas frecuentes
¿Qué es una tabla STRICT en SQLite?
Una tabla STRICT obliga a respetar el tipo declarado en cada columna: si dices que una columna es INTEGER, SQLite va a rechazar cualquier valor que no sea un entero o NULL. Para activarlo basta con añadir la palabra clave STRICT después del paréntesis de cierre del CREATE TABLE. Sin ella, SQLite usa la afinidad de tipos, que convierte los valores cuando puede y los guarda tal cual cuando no.
¿Qué tipos puedo usar en una tabla STRICT?
Solo cinco: INTEGER, REAL, TEXT, BLOB y ANY. Los alias que sí funcionan en tablas normales —VARCHAR, DOUBLE, BOOLEAN, DATETIME— provocan un error en una tabla STRICT. La columna ANY es la vía de escape: acepta cualquier tipo sin hacer conversiones.
¿Conviene usar tablas STRICT en bases de datos SQLite nuevas?
En la mayoría de esquemas nuevos, sí. Las tablas STRICT detectan errores que las tablas normales se tragan en silencio: una cadena que se cuela en una columna INTEGER, una lista serializada por accidente dentro de un REAL. El precio es una palabra clave extra por tabla y renunciar a los nombres de tipo más exóticos. Disponible desde SQLite 3.37 (2021).