Cómo modificar la estructura de una tabla en SQL con ALTER TABLE paso a paso

Imagen educativa en colores azul y violeta que muestra una tabla clientes con las columnas id, nombre, email y fecha_alta, junto a la consulta SQL ALTER TABLE clientes ADD COLUMN telefono VARCHAR(30);, representando cómo modificar la estructura de una tabla en SQL.

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):

columnatiporestricción
idINTPK
nombreVARCHAR(100)NOT NULL
emailVARCHAR(255)
fecha_altaDATE
telefonoVARCHAR(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 usaba CHANGE 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 valores NULL. 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 id no tenga duplicados ni NULL.

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 CHECK pueden 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/DELETE define el comportamiento ante cambios en la tabla referenciada.
  • Elegí CASCADE, SET NULL, RESTRICT o NO ACTION segú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;

9) Agregar o quitar índices relacionados

Los índices no forman parte del estándar ALTER TABLE (se crean con CREATE 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:

  1. Agregar columna como nullable sin default (rápido):
ALTER TABLE clientes ADD COLUMN telefono VARCHAR(30);
  1. Backfill (completar) en batches:
UPDATE clientes
SET telefono = '-'
WHERE telefono IS NULL
-- opcionalmente con filtros por rango/fecha/limit para lotes
;
  1. 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 '-';
  1. 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:

  1. Crear columna nueva:
ALTER TABLE clientes ADD COLUMN id_big BIGINT;
  1. Copiar datos (en lotes si es grande):
UPDATE clientes SET id_big = id;
  1. Actualizar claves foráneas/índices que usen id (recrear apuntando a id_big).
  2. Swappear nombres (renombrar columnas):
ALTER TABLE clientes RENAME COLUMN id TO id_int_legacy;
ALTER TABLE clientes RENAME COLUMN id_big TO id;
  1. 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):

TablaColumnas principalesRestricciones
clientesid (PK), nombre, email (UNIQUE, NOT NULL), país, ciudad, telPK, UNIQUE(email), NOT NULL(email)
pedidosid (PK), cliente_id, total, fechaPK, FK(cliente_id → clientes.id)

14) Compatibilidad y diferencias por motor (resumen rápido)

OperaciónPostgreSQLMySQL/MariaDBSQL ServerOracle
Agregar columnaADD COLUMNADD COLUMNADDADD
Cambiar tipoALTER COLUMN … TYPEMODIFY COLUMNALTER COLUMNMODIFY
Renombrar columnaRENAME COLUMNRENAME COLUMN (8.0+) / CHANGEsp_renameRENAME COLUMN
NOT NULLALTER COLUMN … SET/DROP NOT NULLMODIFY … NOT NULL/NULLALTER COLUMN … NOT NULLMODIFY (col NOT NULL/NULL)
DEFAULTALTER COLUMN … SET/DROP DEFAULTALTER … SET/DROP DEFAULT o MODIFY … DEFAULTADD/DROP CONSTRAINT DEFAULTMODIFY (col DEFAULT …)
Quitar PK/UK/FKDROP CONSTRAINTDROP PRIMARY KEY / DROP INDEX / DROP FOREIGN KEYDROP CONSTRAINTDROP CONSTRAINT
Renombrar tablaALTER TABLE … RENAME TORENAME TABLE … TO …sp_renameRENAME … TO …

15) Errores frecuentes (y cómo evitarlos)

  1. Cambiar a NOT NULL con filas nulas → la sentencia falla.
    • Solución: backfill previo, luego SET NOT NULL.
  2. Agregar columna NOT NULL con DEFAULT en tablas enormes → posible reescritura y bloqueo.
    • Solución: patrón en 4 pasos (agregar nullable → backfill → default → not null).
  3. Cambiar tipo incompatible (p. ej. texto con letras a número) → error o truncamiento.
    • Solución: crear nueva columna, transformar explícitamente, validar, swap.
  4. Quitar columna usada por índice/FK/vista → error de dependencia.
    • Solución: eliminar/ajustar dependencias en orden.
  5. 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

Scroll al inicio