CREATE TABLE

La sentencia CREATE TABLE define una nueva tabla en la base de datos activa. Una tabla es la estructura fundamental de MySQL: organiza los datos en filas y columnas, donde cada columna tiene un nombre, un tipo de datos y opcionalmente restricciones que controlan qué valores puede almacenar.

Sintaxis básica

CREATE TABLE nombre_tabla (
    columna1 tipo_de_dato [restricciones],
    columna2 tipo_de_dato [restricciones],
    ...
    [restricciones_de_tabla]
);

Cada columna se define con un nombre y un tipo de datos. Las restricciones son opcionales pero fundamentales para garantizar la integridad de los datos.

Crear una tabla simple

CREATE TABLE tareas (
    id INT AUTO_INCREMENT PRIMARY KEY,
    titulo VARCHAR(200) NOT NULL,
    completada BOOLEAN DEFAULT FALSE
);
Query OK, 0 rows affected (0.03 sec)

Esta tabla tiene tres columnas. id es un entero que se incrementa automáticamente y actúa como clave primaria. titulo es una cadena de hasta 200 caracteres que no puede ser nula. completada es un booleano que por defecto vale FALSE.

Tipos de datos comunes

Al definir columnas, eliges el tipo de datos que mejor se ajusta a la información que almacenarás. Los más habituales son:

CREATE TABLE ejemplo_tipos (
    -- Números enteros
    cantidad INT,
    cantidad_pequena TINYINT,
    cantidad_grande BIGINT,
 
    -- Números decimales
    precio DECIMAL(10, 2),
    porcentaje FLOAT,
 
    -- Cadenas de texto
    codigo CHAR(5),
    nombre VARCHAR(100),
    descripcion TEXT,
 
    -- Fechas y horas
    fecha_nacimiento DATE,
    hora_entrada TIME,
    creado_en DATETIME,
    actualizado_en TIMESTAMP,
 
    -- Otros
    activo BOOLEAN,
    tipo ENUM('A', 'B', 'C')
);

INT almacena enteros de -2,147,483,648 a 2,147,483,647. DECIMAL(10, 2) almacena números con 10 dígitos totales y 2 decimales, ideal para precios. VARCHAR(100) almacena cadenas de longitud variable hasta 100 caracteres. TEXT almacena textos largos sin límite práctico. DATETIME almacena fecha y hora. TIMESTAMP es similar pero se convierte automáticamente a UTC.

Restricciones de columna

Las restricciones controlan qué valores son válidos para cada columna:

CREATE TABLE empleados_temp (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL UNIQUE,
    salario DECIMAL(10, 2) NOT NULL CHECK (salario > 0),
    departamento VARCHAR(50) DEFAULT 'General',
    fecha_alta DATE NOT NULL
);

NOT NULL impide valores nulos. UNIQUE garantiza que no haya duplicados. PRIMARY KEY combina NOT NULL y UNIQUE, e identifica cada fila de forma única. DEFAULT asigna un valor cuando no se especifica uno. CHECK valida que el valor cumpla una condición. AUTO_INCREMENT genera valores secuenciales automáticamente.

Clave primaria

La clave primaria identifica de forma única cada fila de la tabla. Puede definirse en la columna o como restricción de tabla:

-- Como restricción de columna
CREATE TABLE opcion_a (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100)
);
 
-- Como restricción de tabla
CREATE TABLE opcion_b (
    id INT AUTO_INCREMENT,
    nombre VARCHAR(100),
    PRIMARY KEY (id)
);

Ambas formas son equivalentes. La restricción de tabla es necesaria cuando la clave primaria es compuesta (formada por varias columnas):

CREATE TABLE inscripciones (
    estudiante_id INT,
    curso_id INT,
    fecha_inscripcion DATE DEFAULT (CURRENT_DATE),
    nota DECIMAL(4, 2),
    PRIMARY KEY (estudiante_id, curso_id)
);

Con esta clave primaria compuesta, un estudiante puede inscribirse en varios cursos, y un curso puede tener varios estudiantes, pero la combinación de ambos debe ser única.

Claves foráneas

Las claves foráneas establecen relaciones entre tablas. Garantizan que el valor de una columna exista como clave primaria en otra tabla:

CREATE TABLE departamentos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL
);
 
CREATE TABLE miembros (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    departamento_id INT,
    FOREIGN KEY (departamento_id) REFERENCES departamentos(id)
);

Con esta definición, miembros.departamento_id solo puede contener valores que existan en departamentos.id (o NULL si la columna lo permite). Si intentas insertar un departamento_id que no existe, MySQL devuelve un error.

Acciones referenciales

Las claves foráneas permiten definir qué sucede cuando se elimina o actualiza la fila referenciada:

CREATE TABLE comentarios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    articulo_id INT NOT NULL,
    texto TEXT NOT NULL,
    FOREIGN KEY (articulo_id) REFERENCES articulos(id)
        ON DELETE CASCADE
        ON UPDATE CASCADE
);

ON DELETE CASCADE elimina automáticamente los comentarios cuando se elimina el artículo. ON DELETE SET NULL establece la columna a NULL (la columna no puede ser NOT NULL). ON DELETE RESTRICT impide eliminar el artículo si tiene comentarios. ON UPDATE CASCADE actualiza el valor de la clave foránea si cambia la clave primaria referenciada.

La acción por defecto es RESTRICT, que protege contra eliminaciones o actualizaciones accidentales.

IF NOT EXISTS

Si intentas crear una tabla que ya existe, MySQL devuelve un error:

CREATE TABLE tareas (
    id INT PRIMARY KEY,
    titulo VARCHAR(200)
);
ERROR 1050 (42S01): Table 'tareas' already exists

Para evitar este error:

CREATE TABLE IF NOT EXISTS tareas (
    id INT PRIMARY KEY,
    titulo VARCHAR(200)
);
Query OK, 0 rows affected, 1 warning (0.00 sec)

MySQL genera una advertencia en lugar de un error. La tabla existente no se modifica.

CREATE TABLE con SELECT

Puedes crear una tabla a partir del resultado de una consulta:

CREATE TABLE productos_caros AS
SELECT id, nombre, precio, stock
FROM productos
WHERE precio > 500;
Query OK, 7 rows affected (0.03 sec)
Records: 7  Duplicates: 0  Warnings: 0

La nueva tabla contiene las columnas y los datos del SELECT. Sin embargo, no copia las restricciones (claves primarias, foráneas, índices). Solo copia los tipos de datos y los valores.

Para ver el contenido:

SELECT * FROM productos_caros;
idnombrepreciostock
1iPhone 15 Pro1299.9945
2Samsung Galaxy S24899.9962
3Google Pixel 8699.0038
4Xiaomi 14599.9980
5MacBook Air M31399.0025
6Lenovo ThinkPad X11549.0018
7ASUS ROG Zephyrus1899.9912

CREATE TABLE LIKE

Para crear una tabla con la misma estructura que otra, sin copiar los datos:

CREATE TABLE productos_backup LIKE productos;

A diferencia de CREATE TABLE ... AS SELECT, esta forma sí copia la estructura completa: tipos de datos, claves primarias, índices y restricciones. La tabla queda vacía.

Para copiar también los datos después:

INSERT INTO productos_backup SELECT * FROM productos;

Ver la estructura de una tabla

Para ver cómo está definida una tabla existente:

DESCRIBE productos;
FieldTypeNullKeyDefaultExtra
idintNOPRINULLauto_increment
nombrevarchar(200)NONULL
descripciontextYESNULL
preciodecimal(10,2)NONULL
stockintNO0
categoria_idintYESMULNULL
activotinyint(1)YES1
creado_entimestampYESCURRENT_TIMESTAMPDEFAULT_GENERATED
actualizado_entimestampYESCURRENT_TIMESTAMPDEFAULT_GENERATED on update CURRENT_TIMESTAMP

DESC es un sinónimo de DESCRIBE. Para ver la sentencia CREATE TABLE completa:

SHOW CREATE TABLE productos\G

El \G formatea la salida verticalmente, que es más legible para sentencias largas.

Opciones de tabla

MySQL permite especificar opciones adicionales al crear la tabla:

CREATE TABLE logs (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    mensaje TEXT,
    creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB
  DEFAULT CHARSET=utf8mb4
  COLLATE=utf8mb4_unicode_ci
  COMMENT='Tabla de logs del sistema';

ENGINE define el motor de almacenamiento (InnoDB es el predeterminado y recomendado). DEFAULT CHARSET establece el conjunto de caracteres. COLLATE define las reglas de comparación de cadenas. COMMENT añade una descripción a la tabla.

Buenas prácticas

Usa siempre una clave primaria. Cada tabla debe tener una columna o combinación de columnas que identifique de forma única cada fila. La opción más común es un entero con AUTO_INCREMENT.

Nombra las tablas en plural y en minúsculas con guiones bajos: productos, detalle_pedidos, etiquetas_producto. Esto facilita la lectura y evita problemas de portabilidad entre sistemas operativos.

Define las restricciones apropiadas. NOT NULL en columnas que siempre deben tener valor, UNIQUE donde no se permiten duplicados, claves foráneas para mantener la integridad referencial. Es mejor prevenir datos incorrectos que intentar limpiarlos después.

Elige el tipo de datos más preciso. Usa DECIMAL para dinero (no FLOAT), VARCHAR con un límite razonable para cadenas cortas, TEXT solo para textos realmente largos, y ENUM cuando los valores posibles son un conjunto fijo y pequeño.

Limpieza

Si creaste las tablas de ejemplo de este artículo, puedes eliminarlas:

DROP TABLE IF EXISTS productos_caros;
DROP TABLE IF EXISTS productos_backup;
DROP TABLE IF EXISTS tareas;
DROP TABLE IF EXISTS comentarios;
DROP TABLE IF EXISTS miembros;
DROP TABLE IF EXISTS departamentos;
DROP TABLE IF EXISTS inscripciones;
DROP TABLE IF EXISTS ejemplo_tipos;
DROP TABLE IF EXISTS empleados_temp;
DROP TABLE IF EXISTS opcion_a;
DROP TABLE IF EXISTS opcion_b;
DROP TABLE IF EXISTS logs;

En el siguiente artículo veremos cómo modificar la estructura de una tabla existente con ALTER TABLE.

Escrito por Eduardo Lázaro