Contenido de esta guía
Qué son los tipos de datos SQL
El tipo de dato indica qué valores espera una columna: enteros, texto, fechas o cantidades con decimales, por ejemplo. Elegirlo bien ayuda a conservar el significado del dato, aplicar restricciones y evitar conversiones o cálculos inesperados. Los nombres y el comportamiento exacto dependen del motor de base de datos.
Respuesta rápida: usa enteros para cantidades sin fracción; DECIMAL(p,s) o NUMERIC(p,s) para importes exactos en PostgreSQL, MySQL y SQL Server; un tipo de texto para nombres; y tipos de fecha y hora propios del motor cuando tengas que compararlas o calcular con ellas. En SQLite, considera guardar el dinero en céntimos enteros, porque declarar DECIMAL no garantiza aritmética decimal exacta.
Cómo elegir el tipo según el dato
Empieza con tres preguntas: ¿puede tener fracción?, ¿qué rango y precisión necesita?, ¿el dato es texto, una fecha o una cantidad? Después comprueba las reglas del motor en producción. Esta tabla sirve como punto de partida, no como sustituto de esas reglas.
| Dato | Tipo habitual | Decisión importante |
|---|---|---|
| Unidades, edad, identificador | INTEGER o equivalente | Elige un rango suficiente. Un identificador no debe tratarse como número para hacer cálculos. |
| Precio o importe | DECIMAL(p,s) / NUMERIC(p,s) | p es el total de dígitos y s los decimales. En SQLite, valora céntimos enteros. |
| Medición aproximada | FLOAT, REAL o equivalente | Admite error de representación: evita igualdad exacta y dinero. |
| Nombre, título, descripción | VARCHAR(n), NVARCHAR(n) o TEXT | La longitud y el soporte Unicode varían por motor y configuración. |
| Fecha de nacimiento | DATE | No añadas hora si no existe en el dato. |
| Instante de un evento | Tipo de fecha y hora con zona o convención UTC | Define cómo se interpretará la zona horaria al guardar y leer. |
| Sí / no | BOOLEAN, BIT o entero controlado | Comprueba la representación y limita los valores válidos. |
Precisión: DECIMAL frente a FLOAT
DECIMAL(10,2) permite hasta diez dígitos en total, dos de ellos a la derecha del separador decimal. Es una elección habitual para importes en motores con decimal exacto. FLOAT y REAL representan números aproximados; son útiles para mediciones, pero una suma puede mostrar una pequeña diferencia respecto del decimal esperado. En SQLite, DECIMAL(10,2) tiene afinidad NUMERIC y no equivale a un decimal fijo exacto como en los otros motores citados.
Longitud: VARCHAR, NVARCHAR y TEXT
Si el dato tiene una longitud máxima de negocio, documéntala y valídala. VARCHAR(80) no significa lo mismo en todos los motores: SQLite no hace cumplir ese límite. En SQL Server, NVARCHAR es una opción Unicode y su parámetro n mide pares de bytes, no siempre caracteres visibles. PostgreSQL y MySQL también ofrecen opciones de texto de longitud variable, con diferencias de límites y almacenamiento. No escojas un tipo solo por el nombre parecido.
Fechas, horas y booleanos
Una fecha sin hora es distinta de un instante. PostgreSQL ofrece DATE y TIMESTAMP WITH TIME ZONE; SQL Server ofrece date y datetimeoffset; MySQL ofrece DATE, DATETIME y TIMESTAMP. Define la zona horaria y la forma de presentarla antes de migrar datos. Para banderas, PostgreSQL tiene boolean, MySQL trata BOOLEAN como sinónimo de TINYINT(1) y SQL Server usa bit. SQLite carece de tipos nativos de fecha y booleano: suele guardar fechas como texto ISO 8601 o números, y banderas como 0 y 1.
Comparativa rápida: PostgreSQL, MySQL, SQL Server y SQLite
| Necesidad | PostgreSQL | MySQL | SQL Server | SQLite |
|---|---|---|---|---|
| Entero | integer | INT | int | INTEGER |
| Dinero exacto | numeric(10,2) | DECIMAL(10,2) | decimal(10,2) | INTEGER en céntimos |
| Texto corto | varchar(80) | VARCHAR(80) | nvarchar(80) | TEXT con CHECK si hace falta límite |
| Fecha | date | DATE | date | TEXT ISO 8601, validado |
| Bandera | boolean | BOOLEAN (alias) | bit | INTEGER con CHECK |
La tabla compara intenciones, no declaraciones intercambiables. En particular, una migración desde SQLite necesita revisar validaciones, precisión y fechas. En SQL Server, también existe soporte Unicode con VARCHAR bajo intercalaciones UTF-8; la elección entre VARCHAR y NVARCHAR depende de la configuración y del caso.
Ejemplo comprobado en SQLite
Este ejemplo guarda importes en céntimos para que sumas y filtros usen enteros. Aplica restricciones explícitas al título y a la bandera. La fecha se guarda como texto ISO 8601: la aplicación debe validar que represente una fecha real.
CREATE TABLE productos_tipos_demo (
id INTEGER PRIMARY KEY,
nombre TEXT NOT NULL CHECK (length(nombre) BETWEEN 1 AND 80),
precio_centimos INTEGER NOT NULL CHECK (precio_centimos >= 0),
activo INTEGER NOT NULL CHECK (activo IN (0, 1)),
creado_en TEXT NOT NULL
);
INSERT INTO productos_tipos_demo
(id, nombre, precio_centimos, activo, creado_en)
VALUES (1, 'Cuaderno', 1295, 1, '2026-09-28');
SELECT nombre, precio_centimos, activo
FROM productos_tipos_demo
WHERE precio_centimos >= 1000;| nombre | precio_centimos | activo |
|---|---|---|
| Cuaderno | 1295 | 1 |
El valor 1295 equivale a 12,95 € si la moneda usa dos decimales. Guarda también la divisa si tu aplicación admite más de una; no todas tienen dos decimales. Puedes probar la consulta en el editor SQL del sitio.
Errores frecuentes al elegir tipos de datos
- Guardar importes en FLOAT: una representación aproximada puede alterar comparaciones y sumas. Usa decimal exacto donde exista o unidades menores enteras si el modelo lo permite.
- Suponer que VARCHAR(n) siempre limita: en SQLite la longitud indicada no se impone; añade una restricción
CHECKo valida en la aplicación. - Guardar fechas como texto sin formato definido: formatos mezclados complican ordenar y filtrar. Usa un tipo de fecha nativo cuando exista; en SQLite acuerda un formato ISO 8601 y valida el valor.
- Confundir NULL con falso o cero:
NULLindica ausencia de dato. UsaNOT NULLcuando la columna sea obligatoria y consulta la guía de IS NULL e IS NOT NULL. - Copiar la misma declaración entre motores: prueba rangos, Unicode, zonas horarias y restricciones antes de migrar. Un nombre de tipo similar no garantiza el mismo comportamiento.
Qué debes recordar
- El tipo depende del significado y del rango real del dato.
- Para dinero, prioriza precisión exacta; evita
FLOAT. - Texto, fechas y booleanos cambian de comportamiento entre motores.
- En SQLite, apoya los tipos con
CHECKy validación cuando haga falta.