Al terminar, podrás
- Traducir requisitos de negocio a columnas, claves y restricciones antes de escribir SQL.
- Distinguir qué reglas pertenecen a
CREATE TABLEy qué cambio posterior corresponde aALTER TABLE. - Elegir un índice a partir de una consulta o filtro previsto, no por costumbre.
- Comprobar el estado final del esquema en lugar de dar por bueno un script solo porque no muestra errores.
Recupera lo aprendido: ¿Qué regla impide repetir una pareja de valores y qué regla limita un valor a un rango?
La idea clave: diseña reglas antes de escribir sentencias
Una migración pequeña puede incluir varias decisiones distintas. Mezclarlas sin un plan suele producir columnas ambiguas, restricciones incompletas o índices que no responden a ninguna consulta real. Antes de abrir el editor, separa el requisito en cuatro preguntas: qué entidad vas a guardar, qué estados son inválidos, qué cambia después y cómo se buscarán las filas.
Una aplicación necesita registrar incidencias asociadas a pedidos. Cada incidencia tendrá un identificador, el pedido al que pertenece, un código, un detalle opcional y un estado. Después se añade una prioridad. El equipo consulta habitualmente las incidencias por estado y prioridad.
Convierte el requisito en un plan de esquema
- Identidad. La tabla necesita una clave primaria para distinguir cada incidencia.
- Relación.
pedido_iddebe apuntar a una fila existente depedidos. - Estados válidos. El estado solo admite
'abierta'o'resuelta'y comienza como'abierta'. - Duplicados que no tienen sentido. Un mismo pedido no debe repetir el mismo código de incidencia.
- Evolución. La prioridad se añade después y debe quedar entre 1 y 3, con 2 como valor predeterminado.
- Acceso previsto. El índice seguirá el filtro habitual: primero estado y después prioridad.
Ejemplo guiado: una decisión por capa
Imagina una tabla más pequeña para guardar notas de un pedido. Un primer borrador podría separar la relación y el estado así:
CREATE TABLE notas_pedido (
id INTEGER PRIMARY KEY,
pedido_id INTEGER NOT NULL,
texto TEXT NOT NULL,
FOREIGN KEY (pedido_id) REFERENCES pedidos(id)
);La clave primaria identifica la nota, NOT NULL evita que falten datos esenciales y la clave foránea expresa la relación con pedidos. Si más tarde la aplicación necesita distinguir notas internas y externas, ese cambio debe planificarse como evolución del esquema, no esconderse en una columna que ya significaba otra cosa.
Un error habitual
Usar un índice como si fuera una regla de integridad
Un índice normal no impide estados inválidos. Si necesitas evitar duplicados, usa una restricción UNIQUE o una clave adecuada. Si necesitas impedir valores fuera de un rango, usa CHECK. El índice de esta práctica existe porque hay una consulta prevista por estado y prioridad.
Práctica guiada: construye y evoluciona el esquema
Escribe tres sentencias. El laboratorio no se limita a buscar palabras: comparará el estado final de la tabla, sus restricciones, la relación y el índice con el esquema esperado.
Laboratorio SQL
Diseña incidencias de pedidos
Crea incidencias_pedido con id INTEGER PRIMARY KEY; pedido_id INTEGER NOT NULL relacionado con pedidos(id); codigo TEXT NOT NULL; detalle TEXT opcional; estado TEXT NOT NULL DEFAULT 'abierta' con CHECK que admita solo 'abierta' o 'resuelta'; y UNIQUE (pedido_id, codigo). Después añade prioridad INTEGER NOT NULL DEFAULT 2 con CHECK entre 1 y 3 mediante ALTER TABLE. Por último crea idx_incidencias_estado_prioridad sobre (estado, prioridad), en ese orden.
Resultado esperado: tabla incidencias_pedido con seis columnas, relación con pedidos, unicidad compuesta, reglas CHECK y el índice estado+prioridad.
Ver tablas y datos
Cargando la estructura del ejercicio…
Resuelve primero toda la definición inicial dentro de CREATE TABLE: columnas, clave primaria, relación, UNIQUE y el CHECK del estado.
La segunda sentencia usa ALTER TABLE incidencias_pedido ADD COLUMN. La prioridad necesita tipo, obligatoriedad, valor predeterminado y rango.
El índice final usa exactamente las columnas estado y prioridad, en ese orden.
Solución
CREATE TABLE incidencias_pedido (
id INTEGER PRIMARY KEY,
pedido_id INTEGER NOT NULL,
codigo TEXT NOT NULL,
detalle TEXT,
estado TEXT NOT NULL DEFAULT 'abierta'
CHECK (estado IN ('abierta', 'resuelta')),
UNIQUE (pedido_id, codigo),
FOREIGN KEY (pedido_id) REFERENCES pedidos(id)
);
ALTER TABLE incidencias_pedido
ADD COLUMN prioridad INTEGER NOT NULL DEFAULT 2
CHECK (prioridad BETWEEN 1 AND 3);
CREATE INDEX idx_incidencias_estado_prioridad
ON incidencias_pedido(estado, prioridad);La tabla inicial concentra las reglas que ya conocemos desde el principio. ALTER TABLE representa una evolución posterior y el índice se añade al final porque responde a una forma concreta de consultar las incidencias.
El laboratorio acepta una definición equivalente siempre que el estado final cumpla los requisitos comprobados.
La consulta usa datos ficticios y se ejecuta solo en este navegador.
SQLite requiere que la aplicación configure el cumplimiento de claves foráneas en cada conexión mediante PRAGMA foreign_keys = ON. El laboratorio educativo aplica las claves foráneas directamente para que la práctica compruebe la relación sin pedirte configuración adicional.
Ronda autónoma: diseña antes de ejecutar
Planifica una tabla de revisiones
Sin ejecutar todavía, escribe el esquema de una tabla revisiones_producto con una clave primaria, relación con productos(id), una puntuación de 1 a 5, comentario opcional y una regla que evite más de una revisión del mismo producto por el mismo cliente. Después indica qué consulta justificaría un índice y qué columnas pondrías primero.
Ver una pista
La regla “un cliente no revisa dos veces el mismo producto” necesita una unicidad compuesta. El índice debe derivarse de un filtro u ordenación frecuente, no de una lista automática de columnas.
Ver una solución posible
Una opción es usar UNIQUE (cliente_id, producto_id) y CHECK (puntuacion BETWEEN 1 AND 5). Si la aplicación consulta “revisiones de un producto ordenadas por fecha”, un índice que comience por producto_id puede ser un candidato; la decisión final debe comprobarse con el motor y los datos reales.
Si te bloqueas, separa integridad, evolución y acceso
- Si dudas sobre columnas y tipos, vuelve a CREATE TABLE.
- Si no sabes qué regla evita un estado inválido, repasa claves y restricciones.
- Si el requisito apareció después de crear la tabla, revisa ALTER TABLE.
- Si la duda es de rendimiento, vuelve a índices y empieza por la consulta que quieres acelerar.
Fuentes técnicas consultadas
La práctica usa sintaxis básica y deliberadamente portable, pero el comportamiento exacto de DDL, restricciones e índices depende del motor. La documentación oficial debe ser la referencia cuando prepares una migración real.
- PostgreSQL 18: Constraints.
- PostgreSQL 18: ALTER TABLE.
- PostgreSQL 18: CREATE INDEX.
- SQLite: CREATE TABLE.
- SQLite: ALTER TABLE.
- SQLite: Foreign Key Support.
- MySQL 8.4: ALTER TABLE.
Comprueba si puedes explicarlo
¿UNIQUE (pedido_id, codigo) permite el mismo código en dos pedidos diferentes?
Ver respuesta razonada
Sí. Solo prohíbe repetir la pareja completa. Como ambas columnas son obligatorias, NOT NULL evita además que una referencia o un código ausente eludan esa regla.
Responde antes de abrir la explicación. Si necesitaste ayuda, cierra la respuesta y vuelve a explicarlo con tus palabras antes de dar la lección por aprendida.
Qué debes recordar
- Empieza por el modelo y sus reglas, no por el índice.
- Usa claves y restricciones para expresar estados válidos en la base de datos.
- Trata
ALTER TABLEcomo una evolución que puede depender del motor y de los datos existentes. - Justifica cada índice con una forma concreta de acceso y recuerda su coste de mantenimiento.
- Comprueba el estado final del esquema: que una sentencia termine sin error no demuestra por sí sola que el diseño sea correcto.