Menu

Tipos de datos en SQLite: clases de almacenamiento

Cómo guarda los valores SQLite: las cinco clases de almacenamiento, por qué su tipado es dinámico y los detalles que sorprenden si vienes de Postgres o MySQL.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Cinco clases de almacenamiento, no muchos tipos

SQLite guarda cada valor en una de estas cinco clases de almacenamiento:

  • NULL — la ausencia de valor.
  • INTEGER — un entero con signo, de 1 a 8 bytes según el tamaño.
  • REAL — un número en punto flotante IEEE de 8 bytes.
  • TEXT — una cadena, almacenada con la codificación de la base de datos (normalmente UTF-8).
  • BLOB — bytes en crudo, guardados tal cual los pasaste.

Y ya. No hay un BOOLEAN aparte, ni DATETIME, ni VARCHAR, ni DECIMAL. Otras bases de datos manejan decenas de tipos; SQLite tiene cinco y todo lo demás se construye sobre ellos.

typeof() te muestra la clase de almacenamiento real de cada valor. Vas a ver integer, real, text, blob. Esos cuatro —más null— son todo lo que SQLite conoce.

Tipado dinámico en SQLite

Aquí viene la parte que descoloca a quienes vienen de Postgres o MySQL. En SQLite (sin STRICT), el tipo que declaras en una columna es más bien una sugerencia que un contrato. El tipo real vive en cada valor, no en la columna:

Las dos filas se insertaron sin problema. La columna id guarda un entero en una fila y texto en la otra; body guarda texto y luego un entero. A SQLite le da igual: almacena valores de cualquier clase en cualquier columna.

Esto es el tipado dinámico de SQLite, y es una decisión de diseño consciente. Hace que SQLite sea muy permisivo para prototipos y scripts rápidos. Pero también significa que un typo en tu código puede guardar datos con la forma equivocada en silencio durante años. Si esa concesión te incomoda —y en la mayoría de esquemas en producción debería incomodarte—, las tablas STRICT son la solución. Llegaremos a ellas en breve.

Afinidad de tipos en un párrafo

El tipo declarado en una columna no se ignora: le da a la columna una afinidad. Cuando insertas un valor, SQLite intenta convertirlo hacia la afinidad de la columna siempre que la conversión sea limpia. Una columna TEXT que recibe el número 42 lo guarda como texto '42'; una columna INTEGER que recibe la cadena '42' lo almacena como el entero 42. Si la conversión implicara perder información, se conserva el tipo original.

Fila uno: el entero 42 se convirtió al texto '42', y la cadena '100' pasó al entero 100. Fila dos: '3.5' no se podía pasar a INTEGER sin perder información, así que se quedó como texto. La afinidad de tipos tiene su propia página más adelante — por ahora, quédate con la idea de que el tipo de la columna sigue influyendo en cómo se guarda el dato, aunque no lo imponga.

Booleanos en SQLite

No existe una clase de almacenamiento BOOLEAN. SQLite guarda los booleanos como enteros: 0 para falso y 1 para verdadero:

Las palabras clave TRUE y FALSE se reconocen (desde SQLite 3.23) y se traducen a 1 y 0. Declarar una columna como BOOLEAN le asigna afinidad numérica, pero no la limita a 0/1: sin STRICT, podrías insertar 'maybe' y a SQLite le daría igual.

Fechas y horas en SQLite

Tampoco existe un tipo DATETIME. Tienes que elegir una de estas tres codificaciones, y las funciones de fecha de SQLite funcionan con cualquiera de ellas:

  • TEXT en formato ISO-8601: '2026-04-23 14:30:00'.
  • REAL como número de día juliano.
  • INTEGER como segundos desde la época Unix.

El texto en formato ISO-8601 suele ser la mejor opción: ordena bien como cadena, es legible para humanos y las funciones integradas (date(), time(), datetime(), strftime(), julianday()) lo aceptan sin problema. Elige una codificación por columna y mantenla; mezclar formatos dentro de una misma columna es de esas cosas que te explotan en la cara seis meses después.

VARCHAR, CHAR y otros nombres conocidos

SQLite acepta los nombres de tipos que ya conoces de otras bases de datos: VARCHAR(255), CHAR(10), NVARCHAR, DECIMAL(10,2), DOUBLE, FLOAT, INT, BIGINT, MEDIUMINT. Todos se parsean sin problema. Lo que ocurre por debajo es que cada uno se asigna a una de las cinco clases de almacenamiento según las reglas de afinidad de tipos.

VARCHAR(255) no impone un límite de 255 caracteres: SQLite ignora la longitud. DECIMAL(10, 2) tampoco guarda un decimal de precisión fija; recibe afinidad numérica y se almacena como INTEGER o REAL. Estos nombres existen sólo para que los esquemas copiados desde otras bases de datos sigan funcionando, pero no arrastran las restricciones que sí aplican en otros motores.

Si necesitas aritmética decimal exacta para manejar dinero, guarda los céntimos como INTEGER. El tipo REAL (coma flotante) acabará introduciendo errores de redondeo en el tercer decimal tarde o temprano.

NULL es una clase de almacenamiento

NULL no es simplemente "ausencia de valor": es un valor con su propia clase de almacenamiento, y así lo devuelve typeof():

b se reporta como null. Esto importa porque NULL no es igual a nada — ni siquiera a otro NULL. b = NULL nunca es verdadero; tienes que escribir b IS NULL. Esto se trata a fondo más adelante, en la página sobre operadores y NULL, pero arranca aquí, con la clase de almacenamiento.

Guardar bytes con BLOB

BLOB almacena bytes en crudo, tal cual — útil para imágenes pequeñas, hashes, datos codificados, cualquier cosa que no sea texto ni número:

El literal x'...' te permite escribir blobs en hexadecimal dentro de SQL; desde el código de la aplicación, lo normal es pasar un arreglo de bytes mediante un parámetro. Aplicar length() sobre un blob devuelve la cantidad de bytes, no de caracteres.

Una nota práctica: SQLite almacena blobs grandes sin problema, pero arrastrar un blob de 50 MB en cada consulta que toque esa fila resulta lento. Para archivos grandes, guarda el archivo en disco y conserva solo la ruta en la base de datos.

Lo que te llevas

  • Las cinco clases de almacenamiento — NULL, INTEGER, REAL, TEXT y BLOB — cubren absolutamente todo.
  • El tipo booleano en SQLite son enteros; las fechas se guardan como texto, real o entero (tú eliges).
  • Los tipos de columna declarados son pistas, no contratos (a menos que uses STRICT).
  • VARCHAR(255) y compañía se aceptan al parsear, pero no imponen la longitud ni la precisión que sugieren en otros motores.
  • typeof(value) es tu mejor aliado cuando no tengas claro qué se guardó realmente.

Siguiente paso: afinidad de tipos

El comportamiento de "pista" que dejamos en el aire tiene un conjunto de reglas muy preciso detrás — cinco clases de afinidad, derivadas del nombre del tipo declarado, que se aplican cada vez que insertas un valor. De eso trata la siguiente página, y es la clave para predecir qué hará SQLite realmente con los valores que le pases.

Preguntas frecuentes

¿Qué tipos de datos admite SQLite?

SQLite trabaja con cinco clases de almacenamiento: NULL, INTEGER, REAL, TEXT y BLOB. Cualquier valor de la base de datos termina guardado como una de ellas. Los nombres clásicos como VARCHAR(255), DATETIME o BOOLEAN se aceptan en el CREATE TABLE por compatibilidad, pero internamente se reducen a una de esas cinco a la hora de guardar.

¿SQLite tiene tipo booleano o de fecha y hora?

No como clases independientes. Los booleanos se guardan como INTEGER (0 y 1), aunque SQLite también reconoce las palabras clave TRUE y FALSE. Las fechas y horas se almacenan como TEXT (cadenas ISO-8601), REAL (días julianos) o INTEGER (segundos desde la época Unix); tú eliges la codificación y las funciones de fecha funcionan con las tres.

¿Por qué se dice que SQLite tiene tipado dinámico?

En la mayoría de bases de datos, una columna declarada INTEGER rechaza cadenas. En SQLite (por defecto) el tipo declarado es solo una pista: el tipo real viaja con cada valor, así que una columna TEXT puede acabar guardando un entero si se lo metes. Esa flexibilidad a veces es útil y a veces te da un disgusto. Las tablas STRICT desactivan ese comportamiento.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR