ENUM
ENUM define una columna que solo puede contener un valor de una lista predefinida. Internamente, MySQL almacena cada valor como un entero (1, 2, 3...), lo que hace que sea compacto y rápido de comparar. Es útil para columnas con un conjunto pequeño y estable de opciones como estados, prioridades o categorías fijas.
Sintaxis
CREATE TABLE nombre_tabla (
columna ENUM('valor1', 'valor2', 'valor3') NOT NULL
);Cada valor se define como una cadena entre comillas. MySQL asigna un índice numérico secuencial empezando en 1.
Ejemplo básico
CREATE TABLE tickets (
id INT AUTO_INCREMENT PRIMARY KEY,
titulo VARCHAR(200) NOT NULL,
prioridad ENUM('baja', 'media', 'alta', 'crítica') NOT NULL DEFAULT 'media',
estado ENUM('abierto', 'en progreso', 'resuelto', 'cerrado') NOT NULL DEFAULT 'abierto'
);
INSERT INTO tickets (titulo, prioridad, estado) VALUES
('Error en login', 'alta', 'en progreso'),
('Actualizar docs', 'baja', 'abierto'),
('Caída del servidor', 'crítica', 'resuelto'),
('Mejorar UI', 'media', 'abierto');
SELECT * FROM tickets;| id | titulo | prioridad | estado |
|---|---|---|---|
| 1 | Error en login | alta | en progreso |
| 2 | Actualizar docs | baja | abierto |
| 3 | Caída del servidor | crítica | resuelto |
| 4 | Mejorar UI | media | abierto |
MySQL rechaza valores que no están en la lista:
INSERT INTO tickets (titulo, prioridad) VALUES ('Test', 'urgente');ERROR 1265 (01000): Data truncated for column 'prioridad' at row 1
ENUM en tienda_mysql
La tabla pedidos usa ENUM para el estado del pedido:
SELECT estado, COUNT(*) AS total
FROM pedidos
GROUP BY estado
ORDER BY FIELD(estado, 'pendiente', 'procesando', 'enviado', 'entregado', 'cancelado');| estado | total |
|---|---|
| pendiente | 7 |
| procesando | 4 |
| enviado | 4 |
| entregado | 7 |
| cancelado | 3 |
SELECT id, cliente_id, estado, total
FROM pedidos
WHERE estado = 'cancelado';| id | cliente_id | estado | total |
|---|---|---|---|
| 16 | 12 | cancelado | 699.00 |
| 17 | 1 | cancelado | 49.99 |
| 25 | 19 | cancelado | 149.99 |
Índices numéricos internos
Cada valor ENUM tiene un índice numérico. El primer valor es 1, el segundo es 2, etc. La cadena vacía tiene índice 0:
SELECT
prioridad,
prioridad + 0 AS indice
FROM tickets
ORDER BY prioridad + 0;| prioridad | indice |
|---|---|
| baja | 1 |
| media | 2 |
| alta | 3 |
| crítica | 4 |
Puedes consultar por índice, aunque no es recomendable:
-- Ambas son equivalentes
SELECT * FROM tickets WHERE prioridad = 'alta';
SELECT * FROM tickets WHERE prioridad = 3;Ordenamiento por ENUM
ENUM ordena por el índice numérico, no alfabéticamente. Esto es una ventaja cuando defines los valores en un orden lógico:
SELECT titulo, prioridad
FROM tickets
ORDER BY prioridad;| titulo | prioridad |
|---|---|
| Actualizar docs | baja |
| Mejorar UI | media |
| Error en login | alta |
| Caída del servidor | crítica |
El orden sigue la definición: baja (1), media (2), alta (3), crítica (4). Si ordenaras alfabéticamente, el orden sería: alta, baja, crítica, media, que no tiene sentido lógico.
Para forzar orden alfabético, usa CAST:
SELECT titulo, prioridad FROM tickets ORDER BY CAST(prioridad AS CHAR);Almacenamiento
ENUM es muy eficiente en espacio:
| Valores en ENUM | Bytes |
|---|---|
| 1 a 255 | 1 byte |
| 256 a 65,535 | 2 bytes |
Una columna ENUM con 5 valores ocupa solo 1 byte por fila, mientras que un VARCHAR(20) con los mismos valores podría ocupar 5-21 bytes.
Filtrar con ENUM
Puedes usar todos los operadores habituales:
-- Valores específicos
SELECT titulo FROM tickets WHERE prioridad = 'alta';
-- Múltiples valores con IN
SELECT titulo FROM tickets WHERE estado IN ('abierto', 'en progreso');
-- Comparaciones con índice (prioridad >= alta)
SELECT titulo FROM tickets WHERE prioridad >= 'alta';| titulo |
|---|
| Error en login |
| Caída del servidor |
La comparación >= funciona con el índice numérico: alta (3) y crítica (4) son mayores o iguales que 'alta' (3).
Modificar valores ENUM
Para añadir o cambiar valores, necesitas ALTER TABLE:
-- Añadir un valor al final
ALTER TABLE tickets MODIFY prioridad ENUM('baja', 'media', 'alta', 'crítica', 'bloqueante');
-- Añadir un valor en medio (requiere redefinir toda la lista)
ALTER TABLE tickets MODIFY prioridad ENUM('mínima', 'baja', 'media', 'alta', 'crítica', 'bloqueante');Añadir un valor al final es rápido (solo cambia los metadatos). Insertar un valor en medio o reordenar requiere reconstruir la tabla, porque los índices numéricos cambian.
ENUM y NULL
Si la columna permite NULL, hay tres tipos de valores posibles: los valores definidos, la cadena vacía (si el modo no es estricto) y NULL:
CREATE TABLE test_enum (
valor ENUM('a', 'b', 'c')
);
INSERT INTO test_enum VALUES ('a'), (NULL);
SELECT valor, valor IS NULL AS es_null FROM test_enum;| valor | es_null |
|---|---|
| a | 0 |
| 1 |
ENUM vs CHECK
Una alternativa a ENUM es usar VARCHAR con una restricción CHECK:
-- Con ENUM
estado ENUM('activo', 'inactivo', 'suspendido')
-- Con CHECK
estado VARCHAR(20) CHECK (estado IN ('activo', 'inactivo', 'suspendido'))| Característica | ENUM | VARCHAR + CHECK |
|---|---|---|
| Almacenamiento | 1-2 bytes | Longitud del texto |
| Modificar valores | ALTER TABLE MODIFY | ALTER TABLE DROP/ADD CHECK |
| Portabilidad SQL | Solo MySQL | Estándar SQL |
| Ordenamiento | Por posición definida | Alfabético |
| Ver valores válidos | SHOW COLUMNS | Consultar restricciones |
Si la portabilidad entre bases de datos importa, usa VARCHAR con CHECK. Si el rendimiento y el espacio son prioritarios, usa ENUM.
Desventajas de ENUM
Cambiar valores requiere DDL: Añadir, eliminar o reordenar valores requiere ALTER TABLE, que puede bloquear la tabla en tablas grandes.
No es estándar SQL: ENUM es específico de MySQL. Si migras a PostgreSQL, tendrás que crear un tipo ENUM diferente o usar CHECK.
Los índices cambian: Si insertas un valor nuevo en medio de la lista, los índices numéricos de los valores posteriores cambian, lo que puede romper código que dependa de los índices.
Limpieza
DROP TABLE IF EXISTS tickets;
DROP TABLE IF EXISTS test_enum;En el siguiente artículo veremos SET, similar a ENUM pero permitiendo múltiples valores simultáneos en una columna.
Escrito por Eduardo Lázaro
