Migraciones del esquema
En resumen: Una migración del esquema es un cambio numerado en el esquema de la base de datos que se ejecuta una sola vez y mantiene la base de datos en la misma versión en todas las máquinas.
Problema
«no such column: phone»
Un compañero añade una columna phone a customers en su computadora y escribe el código que la muestra. En su computadora todo funciona. La versión nueva sube al sitio y la página «Clientes» falla con no such column: phone, porque la base de datos del sitio no tiene esa columna. Y una tercera computadora del equipo tiene dos columnas, porque allí alguien la añadió a mano con otro nombre.
El código está en git y todos tienen la misma versión. El esquema de la base de datos necesita lo mismo: escrito, versionado e igual en todas partes.
La idea
Una migración: un cambio numerado
Una migración es un pequeño archivo SQL con un número. Cada cambio del esquema es un archivo nuevo, y los archivos están en git junto al código:
migrations/ 001_create_shop.sql 002_reviews.sql 003_customers_phone.sqlLa base de datos recuerda en una tabla cuáles se han ejecutado, normalmente schema_migrations. Al arrancar (o cuando se publica una versión nueva) la herramienta ejecuta, en orden, solo los archivos que todavía no están en ella. Esta base de datos está en la versión 2:
La migración 3 es el cambio más su registro, juntos en una transacción:
Ejecútala una segunda vez en el mismo cuadro y ALTER TABLE se detiene con «duplicate column name». Por eso la herramienta comprueba schema_migrations antes de ejecutar un archivo.
Míralo
Por qué en una transacción
Si una migración sin transacción se detiene a medias, el primer cambio se queda y falta el registro de la versión. El siguiente intento empieza otra vez desde el principio y tropieza con su propio primer paso. Aquí la segunda sentencia es un error (la misma columna dos veces):
La transacción queda abierta con el primer ALTER TABLE, y el COMMIT nunca llega a la base de datos. Ejecuta ROLLBACK; en el cuadro y la columna phone desaparece: en SQLite y PostgreSQL un cambio de esquema forma parte de la transacción. Corriges el archivo y lo ejecutas de nuevo, y la base de datos está exactamente como estaba.
Pruébalo
Migración 3: puntos de fidelidad
Escribe la migración 3 para la base de datos en la versión 2: una columna loyalty_points en customers (un entero, obligatorio, 0 por defecto) y el registro (3, 'loyalty_points', '2026-10-25') en schema_migrations, en una transacción.
Solución
BEGIN;
ALTER TABLE customers ADD COLUMN loyalty_points INTEGER NOT NULL DEFAULT 0;
INSERT INTO schema_migrations VALUES (3, 'loyalty_points', '2026-10-25');
COMMIT;Sin DEFAULT 0, SQLite no añade una columna NOT NULL a una tabla que tiene filas, porque los 20 clientes no tienen valor para ella. Con DEFAULT 0 cada uno recibe 0. El registro en schema_migrations va en la misma transacción para que la migración no se ejecute dos veces.
La idea
Las herramientas
Nadie escribe a mano la comprobación de «qué migración se ha ejecutado». Cada lenguaje tiene una herramienta que lleva la tabla de versiones y ejecuta los archivos en orden:
- Java: Flyway o Liquibase (
V3__customers_phone.sql); - C#: EF Core Migrations (
dotnet ef migrations add CustomersPhone) escribe la migración a partir del cambio en las clases; - Python: Alembic (para SQLAlchemy) o las migraciones de Django;
- JavaScript: Prisma Migrate, Knex o node-pg-migrate.
Algunas escriben también un paso inverso (down) que deshace la migración. En un sitio con datos reales, volver atrás rara vez es un DROP COLUMN: si la columna nueva ya contiene datos, el paso inverso los pierde. Por eso «volver» suele ser una migración nueva hacia delante.
Míralo
Cambiar una base de datos en marcha: por pasos
El sitio no se detiene mientras se publica la nueva versión: durante un tiempo funcionan a la vez el código viejo y el nuevo. Si la migración renombra city a town, el código viejo falla en ese mismo segundo. Por eso el cambio se hace en tres pasos:
- Ampliar. Añadir
towny rellenarla desdecity. El código viejo no lo nota. - Migrar. El código nuevo escribe en las dos y lee
town. Esperas hasta que el código viejo haya desaparecido de todas partes. - Contraer. Una migración aparte, posterior, quita
city.
Ejercicio
Nombre y apellido por separado
La tienda quiere saludar a los clientes por su nombre («Hola, Maria»). Haz el primer paso (ampliar): añade las columnas first_name y last_name a customers y rellénalas a partir de name (cada nombre son dos palabras separadas por un espacio). La columna name se queda.
Solución
ALTER TABLE customers ADD COLUMN first_name TEXT;
ALTER TABLE customers ADD COLUMN last_name TEXT;
UPDATE customers
SET first_name = substr(name, 1, instr(name, ' ') - 1),
last_name = substr(name, instr(name, ' ') + 1);instr(name, ' ') da la posición del espacio, y substr toma el texto de antes y de después. La columna name se queda, porque el código viejo todavía la lee. Quitarla es el último paso, en una migración aparte.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: ALTER TABLE: cambiar una tabla · ACID: todo o nada · BEGIN, COMMIT, ROLLBACK · Conectarse a la base de datos desde el código
- Continúa en: Pools de conexiones, copias de seguridad y permisos
- Ejercicios sobre el tema: La base de datos en el programa