Skip to content

Tipos de datos ​

Cada columna de una tabla tiene un tipo de dato que define qué puede guardar: números, texto, fechas... Elegir bien el tipo evita errores (como precios que pierden centavos), ahorra espacio y hace tus consultas más rápidas. En esta lección verás los tipos más usados y sus diferencias entre MySQL, PostgreSQL y SQLite.

Concepto ​

El tipo de dato es como el tamaño y forma de un cajón: en un cajón para cucharas no caben platos. Si declaras una columna como número entero, la BD rechazará (o convertirá) un texto como 'hola'.

Elegir el tipo correcto te da:

  • Validación automática: no se cuelan datos absurdos.
  • Operaciones correctas: sumar números, restar fechas, ordenar alfabéticamente.
  • Rendimiento: un INT ocupa 4 bytes; el mismo número guardado como texto ocupa más y se compara más lento.

Tipos numéricos ​

Enteros ​

TipoBytesRango aproximadoUso típico
SMALLINT2-32 mil a 32 milEdades, cantidades pequeñas
INT / INTEGER4-2,100 millones a 2,100 millonesIDs, stock, cantidades
BIGINT8±9 trillonesIDs de tablas enormes, contadores

MySQL además tiene TINYINT (1 byte) y el modificador UNSIGNED (solo positivos, doble de rango).

Decimales: el tema del dinero ​

TipoExactoUso
DECIMAL(p, s) / NUMERIC(p, s)SíDinero, cantidades exactas
FLOAT / REAL / DOUBLENo (aproximado)Medidas científicas, coordenadas

DECIMAL(10,2) significa: 10 dígitos en total, 2 de ellos después del punto. Máximo: 99999999.99.

sql
-- Prueba esto en PostgreSQL o MySQL:
SELECT 0.1 + 0.2;                                   -- con DECIMAL: 0.3
SELECT CAST(0.1 AS DOUBLE PRECISION) + CAST(0.2 AS DOUBLE PRECISION);
-- resultado: 0.30000000000000004  ← error de redondeo binario

Nunca uses FLOAT para dinero

Los tipos de punto flotante guardan aproximaciones binarias. Tras miles de operaciones aparecen centavos fantasma en los reportes. Para precios, saldos y totales usa siempre DECIMAL(10,2) (o NUMERIC en PostgreSQL).

Tipos de texto ​

TipoDescripciónEjemplo de uso
CHAR(n)Longitud fija; rellena con espaciosCódigos de país 'MX', CURP (18)
VARCHAR(n)Longitud variable hasta n caracteresNombres, emails, títulos
TEXTTexto largo sin límite prácticoDescripciones, artículos de blog
sql
CREATE TABLE ejemplo_texto (
  pais CHAR(2),            -- siempre 2 letras: 'MX', 'AR'
  nombre VARCHAR(100),     -- hasta 100 caracteres
  biografia TEXT           -- texto largo
);

Buena práctica

Ponle a VARCHAR un límite razonable: VARCHAR(100) para nombres, VARCHAR(150)–VARCHAR(255) para emails. Sirve como validación extra. En MySQL usa el charset utf8mb4 para soportar acentos y emojis (lo verás en utf8mb4 y collation).

Fechas y horas ​

TipoGuardaEjemplo
DATESolo fecha'2024-05-02'
TIMESolo hora'14:30:00'
DATETIME (MySQL) / TIMESTAMPFecha y hora'2024-05-02 14:30:00'
TIMESTAMPTZ (PostgreSQL)Fecha, hora y zona horaria'2024-05-02 14:30:00-06'

El formato estándar es ISO 8601: AAAA-MM-DD. Úsalo siempre al escribir fechas; '02/05/2024' es ambiguo (¿2 de mayo o 5 de febrero?).

sql
-- Fecha y hora actuales
SELECT CURRENT_DATE;        -- 2024-06-20
SELECT CURRENT_TIMESTAMP;   -- 2024-06-20 10:15:42

Buena práctica

Para fechas de eventos (cuándo se creó un pedido) guarda la hora en UTC o usa un tipo con zona horaria (TIMESTAMPTZ en PostgreSQL). Convertir a la hora local del usuario es trabajo de la aplicación.

Booleanos ​

SGBDTipoValores
PostgreSQLBOOLEANTRUE, FALSE, NULL
MySQLBOOLEAN (alias de TINYINT(1))1, 0 (acepta TRUE/FALSE)
SQLiteNo tiene; usa INTEGER1, 0
sql
CREATE TABLE usuarios (
  id INT PRIMARY KEY,
  activo BOOLEAN NOT NULL DEFAULT TRUE
);

Otros tipos útiles ​

TipoDisponible enPara qué
ENUM('a','b')MySQL (PostgreSQL con CREATE TYPE)Lista cerrada de valores
JSON / JSONBMySQL / PostgreSQLDatos semiestructurados
UUIDPostgreSQL (MySQL: CHAR(36) o BINARY(16))Identificadores únicos globales
BLOB / BYTEAMySQL / PostgreSQLDatos binarios (mejor guarda archivos fuera de la BD)

NULL: la ausencia de valor ​

NULL significa "desconocido" o "no aplica". No es cero, ni texto vacío, ni falso.

ValorSignificado
0Sabemos que es cero
''Sabemos que es un texto vacío
NULLNo sabemos / no existe

Reglas importantes:

  • Cualquier operación con NULL da NULL: 5 + NULL es NULL.
  • NULL = NULL no es verdadero (es NULL). Para preguntar se usa IS NULL o IS NOT NULL.
  • Usa NOT NULL en las columnas obligatorias.
sql
-- MAL: nunca devuelve filas
SELECT * FROM productos WHERE categoria_id = NULL;

-- BIEN
SELECT * FROM productos WHERE categoria_id IS NULL;

Resultado (con nuestros datos):

idnombrecategoria_idpreciostock
8Cable USB-CNULL99.00100

Para reemplazar un NULL por un valor por defecto en una consulta usa COALESCE:

sql
SELECT nombre, COALESCE(ciudad, 'Sin ciudad') AS ciudad FROM clientes;

Tabla comparativa por SGBD ​

NecesidadMySQL / MariaDBPostgreSQLSQLite
EnteroINTINTEGERINTEGER
ID autoincrementalINT AUTO_INCREMENTINT GENERATED ALWAYS AS IDENTITYINTEGER PRIMARY KEY
DineroDECIMAL(10,2)NUMERIC(10,2)NUMERIC (guarda como real)
Texto cortoVARCHAR(n)VARCHAR(n) o TEXTTEXT
Texto largoTEXT, LONGTEXTTEXTTEXT
FechaDATEDATETEXT en ISO 8601
Fecha y horaDATETIME, TIMESTAMPTIMESTAMP, TIMESTAMPTZTEXT
BooleanoBOOLEAN (=TINYINT(1))BOOLEANINTEGER 0/1
JSONJSONJSON, JSONBTEXT + funciones JSON

SQLite es flexible

SQLite usa "afinidad de tipos": acepta casi cualquier valor en cualquier columna. Es cómodo para aprender, pero en MySQL y PostgreSQL los tipos se respetan con más rigor.

Ejemplo: la tabla productos con tipos bien elegidos ​

sql
CREATE TABLE productos (
  id INT PRIMARY KEY,                 -- entero: identificador
  nombre VARCHAR(100) NOT NULL,       -- texto corto obligatorio
  categoria_id INT NULL,              -- puede no tener categoría
  precio DECIMAL(10,2) NOT NULL,      -- dinero: exacto
  stock INT NOT NULL DEFAULT 0        -- entero, 0 si no se indica
);

Paso a paso: cómo elegir un tipo ​

  1. ¿Es un número con el que harás cuentas? → INT o DECIMAL. ¿Es dinero? → DECIMAL.
  2. ¿Es un "número" que en realidad es un código (teléfono, código postal, CURP)? → texto (VARCHAR). El código postal 01000 perdería su cero inicial como número.
  3. ¿Es una fecha? → DATE/TIMESTAMP, nunca texto.
  4. ¿Es sí/no? → BOOLEAN.
  5. ¿Es obligatorio? → NOT NULL. ¿Tiene un valor típico? → DEFAULT.

Error común

Guardar teléfonos como INT: se pierden ceros iniciales, no caben los de 10+ dígitos en algunos tipos y no puedes guardar +52. Un teléfono es texto: VARCHAR(20).

Ejercicios ​

  1. Elige el tipo para: a) precio de un curso, b) código postal, c) fecha de nacimiento, d) ¿el usuario aceptó términos?, e) descripción larga de un producto, f) número de piso de un edificio.
  2. ¿Qué devuelve SELECT 10 + NULL;? ¿Por qué?
  3. Escribe la definición de la tabla clientes del curso con tipos adecuados (id, nombre, email, ciudad opcional, fecha_registro).
  4. ¿Por qué esta consulta no devuelve nada aunque haya clientes sin ciudad? SELECT * FROM clientes WHERE ciudad = NULL;
Ver solución
  1. a) DECIMAL(10,2), b) VARCHAR(10) (o CHAR(5) en México), c) DATE, d) BOOLEAN, e) TEXT, f) SMALLINT.
  2. NULL. Cualquier operación aritmética con un valor desconocido produce un resultado desconocido.
sql
CREATE TABLE clientes (
  id INT PRIMARY KEY,
  nombre VARCHAR(100) NOT NULL,
  email VARCHAR(150) NOT NULL UNIQUE,
  ciudad VARCHAR(80),
  fecha_registro DATE NOT NULL
);
  1. Porque comparar con NULL usando = nunca es verdadero. Debe ser WHERE ciudad IS NULL.

Resumen ​

  • Cada columna tiene un tipo: elegirlo bien valida datos y mejora el rendimiento.
  • Enteros: INT/BIGINT. Dinero: siempre DECIMAL(10,2).
  • Texto: VARCHAR(n) para datos cortos, TEXT para largos. Teléfonos y códigos postales son texto.
  • Fechas en formato ISO AAAA-MM-DD con tipos DATE o TIMESTAMP.
  • NULL es "desconocido": compáralo con IS NULL y reemplázalo con COALESCE.

Academia Web — aprende, copia y construye.