Cuando empezás con bases de datos, lo común es crear tablas y consultarlas. Pero muy pronto vas a necesitar cambiar la estructura: agregar una columna, renombrar otra, declarar una clave foránea, hacer un campo obligatorio, etc. Para eso existe ALTER TABLE, la instrucción que te permite evolucionar tu esquema sin recrearlo desde cero.
En esta guía aprenderás, paso a paso y desde cero, a usar ALTER TABLE para las operaciones más frecuentes, con ejemplos claros y notas de compatibilidad entre motores (MySQL/MariaDB, PostgreSQL, SQL Server y Oracle). También veremos trucos para hacer cambios seguros en producción y un checklist final para evitar sorpresas.
1) Concepto y reglas básicas de ALTER TABLE
ALTER TABLE sirve para modificar la definición de una tabla ya existente. Con él podés:
- Agregar, renombrar o eliminar columnas.
- Cambiar el tipo de dato o las restricciones (NOT NULL, DEFAULT).
- Agregar o quitar restricciones:
PRIMARY KEY,UNIQUE,CHECK,FOREIGN KEY. - Renombrar la tabla.
- En algunos motores, reordenar columnas o cambiar comentarios.
Buenas prácticas generales
- Probá los cambios en un entorno de desarrollo primero.
- Planeá un rollback (cómo volver atrás).
- Si la tabla es grande, cuidá el tiempo de bloqueo y el impacto en producción.
- Documentá la versión del motor porque la sintaxis puede variar.
2) Crear una tabla de ejemplo
Usaremos esta tabla simple para practicar:
CREATE TABLE clientes (
id INT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
email VARCHAR(255),
fecha_alta DATE
);
Repaso de creación en CREATE TABLE.
3) Agregar columnas con ADD COLUMN
3.1 Agregar una columna simple
ALTER TABLE clientes
ADD COLUMN telefono VARCHAR(30);
La tabla queda así (esquema simplificado):
| columna | tipo | restricción |
|---|---|---|
| id | INT | PK |
| nombre | VARCHAR(100) | NOT NULL |
| VARCHAR(255) | ||
| fecha_alta | DATE | |
| telefono | VARCHAR(30) |
3.2 Agregar varias columnas en un solo comando
Muchos motores permiten separar con comas:
ALTER TABLE clientes
ADD COLUMN pais VARCHAR(50),
ADD COLUMN ciudad VARCHAR(80);
3.3 Agregar una columna con DEFAULT y NOT NULL
Cuidado: en tablas grandes, algunos motores reescriben la tabla si agregás una columna NOT NULL con DEFAULT. Estrategia segura más abajo.
ALTER TABLE clientes
ADD COLUMN activo BOOLEAN DEFAULT TRUE;
Ahora cada fila existente tendrá activo = TRUE salvo que lo cambies.
4) Cambiar el tipo de una columna (ALTER COLUMN … TYPE/MODIFY)
La sintaxis varía por motor:
- PostgreSQL
ALTER TABLE clientes ALTER COLUMN telefono TYPE VARCHAR(40);Si hay que transformar el dato:ALTER TABLE clientes ALTER COLUMN telefono TYPE VARCHAR(40) USING telefono::VARCHAR(40); - MySQL/MariaDB
ALTER TABLE clientes MODIFY COLUMN telefono VARCHAR(40); - SQL Server
ALTER TABLE clientes ALTER COLUMN telefono VARCHAR(40); - Oracle
ALTER TABLE clientes MODIFY (telefono VARCHAR2(40));
Consejo: si el cambio es complejo (p. ej., TEXT → INT), usá el patrón “columna nueva + copia + swap” (lo vemos en la sección de migraciones seguras).
5) Renombrar una columna
- PostgreSQL
ALTER TABLE clientes RENAME COLUMN telefono TO tel; - MySQL 8.0+
ALTER TABLE clientes RENAME COLUMN telefono TO tel;(En MySQL antiguos se usabaCHANGE COLUMN telefono tel VARCHAR(30)) - SQL Server
EXEC sp_rename 'dbo.clientes.telefono', 'tel', 'COLUMN'; - Oracle
ALTER TABLE clientes RENAME COLUMN telefono TO tel;
6) Hacer un campo obligatorio u opcional (SET/DROP NOT NULL)
- PostgreSQL
ALTER TABLE clientes ALTER COLUMN email SET NOT NULL; -- hacerlo obligatorio ALTER TABLE clientes ALTER COLUMN email DROP NOT NULL; -- volverlo opcional - MySQL/MariaDB (se hace vía
MODIFY)ALTER TABLE clientes MODIFY COLUMN email VARCHAR(255) NOT NULL; ALTER TABLE clientes MODIFY COLUMN email VARCHAR(255) NULL; - SQL Server
ALTER TABLE clientes ALTER COLUMN email VARCHAR(255) NOT NULL; - Oracle
ALTER TABLE clientes MODIFY (email NOT NULL); ALTER TABLE clientes MODIFY (email NULL);
Antes de marcar
NOT NULL, verificá que no existan valoresNULL. De lo contrario fallará.
7) Establecer o quitar valores por defecto (DEFAULT)
- PostgreSQL
ALTER TABLE clientes ALTER COLUMN pais SET DEFAULT 'Argentina'; ALTER TABLE clientes ALTER COLUMN pais DROP DEFAULT; - MySQL/MariaDB
ALTER TABLE clientes ALTER COLUMN pais SET DEFAULT 'Argentina'; -- o: ALTER TABLE clientes MODIFY COLUMN pais VARCHAR(50) DEFAULT 'Argentina'; ALTER TABLE clientes ALTER COLUMN pais DROP DEFAULT; - SQL Server
En general se hace con una constraint por defecto:ALTER TABLE clientes ADD CONSTRAINT DF_clientes_pais DEFAULT 'Argentina' FOR pais; ALTER TABLE clientes DROP CONSTRAINT DF_clientes_pais; - Oracle
ALTER TABLE clientes MODIFY (pais DEFAULT 'Argentina'); ALTER TABLE clientes MODIFY (pais DEFAULT NULL);
8) Agregar o quitar restricciones (PRIMARY KEY, UNIQUE, CHECK, FOREIGN KEY)
Repaso de conceptos: PRIMARY KEY, FOREIGN KEY.
8.1 Agregar PRIMARY KEY (en tabla ya existente)
Si la tabla fue creada sin PK:
ALTER TABLE clientes
ADD CONSTRAINT pk_clientes PRIMARY KEY (id);
Asegurate de que
idno tenga duplicados niNULL.
8.2 Agregar UNIQUE
ALTER TABLE clientes
ADD CONSTRAINT uq_clientes_email UNIQUE (email);
8.3 Agregar CHECK (regla de validación)
ALTER TABLE clientes
ADD CONSTRAINT ck_clientes_email_ar
CHECK (email LIKE '%.%' AND email LIKE '%@%');
En motores antiguos de MySQL los
CHECKpueden no aplicarse estrictamente; revisá tu versión.
8.4 Agregar FOREIGN KEY (relación con otra tabla)
Supongamos que tenemos pedidos(id, cliente_id, total, fecha):
ALTER TABLE pedidos
ADD CONSTRAINT fk_pedidos_clientes
FOREIGN KEY (cliente_id) REFERENCES clientes(id)
ON UPDATE CASCADE
ON DELETE RESTRICT;
ON UPDATE/DELETEdefine el comportamiento ante cambios en la tabla referenciada.- Elegí
CASCADE,SET NULL,RESTRICToNO ACTIONsegún tu caso.
8.5 Quitar restricciones
- Genérico (PostgreSQL, SQL Server, Oracle):
ALTER TABLE clientes DROP CONSTRAINT ck_clientes_email_ar; ALTER TABLE clientes DROP CONSTRAINT uq_clientes_email; ALTER TABLE clientes DROP CONSTRAINT pk_clientes; - MySQL/MariaDB
- Quitar PK:
ALTER TABLE clientes DROP PRIMARY KEY; - Quitar UNIQUE:
ALTER TABLE clientes DROP INDEX uq_clientes_email; - Quitar FK:
ALTER TABLE pedidos DROP FOREIGN KEY fk_pedidos_clientes;
- Quitar PK:
9) Agregar o quitar índices relacionados
Los índices no forman parte del estándar
ALTER TABLE(se crean conCREATE INDEX), pero se relacionan con los cambios de esquema. Más info en INDEX.
Crear índice para acelerar búsquedas por email:
CREATE INDEX idx_clientes_email ON clientes(email);
Borrarlo:
- PostgreSQL/Oracle:
DROP INDEX idx_clientes_email; - MySQL:
DROP INDEX idx_clientes_email ON clientes; - SQL Server:
DROP INDEX idx_clientes_email ON dbo.clientes;
10) Eliminar columnas con DROP COLUMN
ALTER TABLE clientes
DROP COLUMN telefono;
Cuidado si la columna participa en una FK, índice, vista o procedimiento. Primero remové la dependencia.
11) Renombrar una tabla
- PostgreSQL
ALTER TABLE clientes RENAME TO clientes_legacy; - MySQL
RENAME TABLE clientes TO clientes_legacy; - SQL Server
EXEC sp_rename 'dbo.clientes', 'clientes_legacy'; - Oracle
RENAME clientes TO clientes_legacy;
12) Cambios seguros en producción (patrones recomendados)
En tablas grandes, ciertos ALTER TABLE pueden bloquear escritura/lectura o reescribir la tabla (costoso). Estas estrategias te ayudan a minimizar riesgos:
12.1 Hacer una columna obligatoria con default (sin bloquear)
Objetivo: telefono debe ser NOT NULL con default '-'.
Patrón en 4 pasos:
- Agregar columna como nullable sin default (rápido):
ALTER TABLE clientes ADD COLUMN telefono VARCHAR(30);
- Backfill (completar) en batches:
UPDATE clientes
SET telefono = '-'
WHERE telefono IS NULL
-- opcionalmente con filtros por rango/fecha/limit para lotes
;
- Agregar DEFAULT (no reescribe histórico en la mayoría de motores modernos):
ALTER TABLE clientes
ALTER COLUMN telefono SET DEFAULT '-'; -- PG
-- MySQL: ALTER TABLE clientes MODIFY COLUMN telefono VARCHAR(30) DEFAULT '-';
- Marcar NOT NULL (cuando no queden NULLs):
ALTER TABLE clientes
ALTER COLUMN telefono SET NOT NULL; -- PG
-- MySQL: ALTER TABLE clientes MODIFY COLUMN telefono VARCHAR(30) NOT NULL DEFAULT '-';
12.2 Cambiar el tipo de una columna sin downtime (swap)
Queremos pasar id de INT a BIGINT:
- Crear columna nueva:
ALTER TABLE clientes ADD COLUMN id_big BIGINT;
- Copiar datos (en lotes si es grande):
UPDATE clientes SET id_big = id;
- Actualizar claves foráneas/índices que usen
id(recrear apuntando aid_big). - Swappear nombres (renombrar columnas):
ALTER TABLE clientes RENAME COLUMN id TO id_int_legacy;
ALTER TABLE clientes RENAME COLUMN id_big TO id;
- Borrar la vieja cuando estés seguro:
ALTER TABLE clientes DROP COLUMN id_int_legacy;
Este patrón evita operaciones “pesadas” que reescriben toda la tabla de una sola vez.
13) Caso completo: de tabla básica a tabla con reglas y relaciones
Punto de partida:
CREATE TABLE clientes (
id INT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
email VARCHAR(255),
fecha_alta DATE
);
Paso 1: Agregar columnas de contacto
ALTER TABLE clientes
ADD COLUMN pais VARCHAR(50),
ADD COLUMN ciudad VARCHAR(80),
ADD COLUMN telefono VARCHAR(30);
Paso 2: Marcar email como único y obligatorio
-- Backfill: asegurate de que no haya NULL y no haya duplicados
UPDATE clientes SET email = CONCAT('noemail+', id, '@example.com') WHERE email IS NULL;
ALTER TABLE clientes
ALTER COLUMN email SET NOT NULL; -- PG
ALTER TABLE clientes
ADD CONSTRAINT uq_clientes_email UNIQUE (email);
Paso 3: Crear tabla pedidos y relacionarla
CREATE TABLE pedidos (
id INT PRIMARY KEY,
cliente_id INT NOT NULL,
total NUMERIC(12,2) NOT NULL,
fecha DATE NOT NULL
);
ALTER TABLE pedidos
ADD CONSTRAINT fk_pedidos_clientes
FOREIGN KEY (cliente_id) REFERENCES clientes(id)
ON UPDATE CASCADE
ON DELETE RESTRICT;
Paso 4: Agregar índices útiles
CREATE INDEX idx_pedidos_fecha ON pedidos(fecha);
CREATE INDEX idx_clientes_ciudad ON clientes(ciudad);
Resultado conceptual (esquema):
| Tabla | Columnas principales | Restricciones |
|---|---|---|
| clientes | id (PK), nombre, email (UNIQUE, NOT NULL), país, ciudad, tel | PK, UNIQUE(email), NOT NULL(email) |
| pedidos | id (PK), cliente_id, total, fecha | PK, FK(cliente_id → clientes.id) |
14) Compatibilidad y diferencias por motor (resumen rápido)
| Operación | PostgreSQL | MySQL/MariaDB | SQL Server | Oracle |
|---|---|---|---|---|
| Agregar columna | ADD COLUMN | ADD COLUMN | ADD | ADD |
| Cambiar tipo | ALTER COLUMN … TYPE | MODIFY COLUMN | ALTER COLUMN | MODIFY |
| Renombrar columna | RENAME COLUMN | RENAME COLUMN (8.0+) / CHANGE | sp_rename | RENAME COLUMN |
| NOT NULL | ALTER COLUMN … SET/DROP NOT NULL | MODIFY … NOT NULL/NULL | ALTER COLUMN … NOT NULL | MODIFY (col NOT NULL/NULL) |
| DEFAULT | ALTER COLUMN … SET/DROP DEFAULT | ALTER … SET/DROP DEFAULT o MODIFY … DEFAULT | ADD/DROP CONSTRAINT DEFAULT | MODIFY (col DEFAULT …) |
| Quitar PK/UK/FK | DROP CONSTRAINT | DROP PRIMARY KEY / DROP INDEX / DROP FOREIGN KEY | DROP CONSTRAINT | DROP CONSTRAINT |
| Renombrar tabla | ALTER TABLE … RENAME TO | RENAME TABLE … TO … | sp_rename | RENAME … TO … |
15) Errores frecuentes (y cómo evitarlos)
- Cambiar a
NOT NULLcon filas nulas → la sentencia falla.- Solución: backfill previo, luego
SET NOT NULL.
- Solución: backfill previo, luego
- Agregar columna
NOT NULLconDEFAULTen tablas enormes → posible reescritura y bloqueo.- Solución: patrón en 4 pasos (agregar nullable → backfill → default → not null).
- Cambiar tipo incompatible (p. ej. texto con letras a número) → error o truncamiento.
- Solución: crear nueva columna, transformar explícitamente, validar, swap.
- Quitar columna usada por índice/FK/vista → error de dependencia.
- Solución: eliminar/ajustar dependencias en orden.
- Renombrar columnas/tables sin actualizar código → rompe consultas y apps.
- Solución: búsqueda global de referencias, capa de vistas de compatibilidad si hace falta.
16) Checklist antes de ejecutar ALTER TABLE
- ¿Probaste en dev y mediste tiempos en una copia similar de datos?
- ¿Tenés respaldo/rollback y ventana de mantenimiento si aplica?
- ¿Verificaste dependencias (FK, índices, vistas, triggers, jobs)?
- ¿Tu cambio requiere backfill? ¿En lotes?
- ¿El cambio es portable entre motores o documentaste la variante?
- ¿Actualizaste documentación y notificaste a quienes consumen el esquema?
17) Conclusión
ALTER TABLE es la herramienta para evolucionar tu base de datos de manera controlada. Con los patrones y ejemplos de esta guía podés:
- Agregar/renombrar/eliminar columnas.
- Cambiar tipos y restricciones con seguridad.
- Declarar claves primarias, foráneas y reglas de negocio.
- Minimizar riesgos en producción con estrategias graduales.
Aplicá estas prácticas y tu esquema crecerá sin sobresaltos, con cambios auditables y predecibles.
📚 Artículos relacionados
- Diferencia entre ALTER TABLE ADD COLUMN y ALTER TABLE MODIFY COLUMN en SQL
Explicación clara y práctica sobre las diferencias entre agregar nuevas columnas y modificar columnas existentes, con ejemplos en distintos motores de bases de datos. - Cómo usar ALTER TABLE DROP COLUMN en SQL con ejemplos prácticos
Ejemplos detallados que muestran cómo eliminar columnas de una tabla, sus efectos en los datos existentes y las buenas prácticas para evitar errores. - Renombrar columnas y tablas en SQL con ALTER TABLE RENAME
Paso a paso para cambiar nombres de tablas y columnas, incluyendo compatibilidad entre MySQL, PostgreSQL, SQL Server y Oracle. - Impacto en el rendimiento al usar ALTER TABLE en tablas grandes
Explicación del impacto en el rendimiento de ALTER TABLE cuando se aplica en tablas con millones de registros, y estrategias para minimizar demoras. - ALTER TABLE en SQL con restricciones PRIMARY KEY y FOREIGN KEY explicados
Guía práctica para agregar o eliminar claves primarias y foráneas con ALTER TABLE, con ejemplos de integridad referencial y buenas prácticas de diseño.
