CREATE TABLE agrega una tabla nueva a una base de datos. Le das un nombre a la tabla y enumeras sus columnas, cada una con un tipo de dato y las reglas (restricciones) que deben cumplir sus valores. Los ejemplos funcionan en PostgreSQL, MySQL, SQLite y SQL Server.
Cómo usar CREATE TABLE
Ponle nombre a la tabla y luego enumera sus columnas entre paréntesis, separadas por comas. Cada columna lleva un nombre, un tipo de dato y, opcionalmente, restricciones como PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT o CHECK:
CREATE TABLE table_name (
column_name data_type constraints,
another_column data_type constraints
);
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
country CHAR(2) DEFAULT 'US',
signed_up DATE
);
INSERT INTO customers (id, name, email, signed_up)
VALUES (1, 'Ana Lima', 'ana@example.com', '2026-03-02');
SELECT * FROM customers;
-- Output:
-- id | name | email | country | signed_up
-- ---+----------+-----------------+---------+-----------
-- 1 | Ana Lima | ana@example.com | US | 2026-03-02
La tabla nueva está vacía hasta que le insertas filas. Este insert omitió country, así que la fila recibió el valor predeterminado, US.
Reglas que debes conocer
-
SQLite no valida tipos ni longitudes. Donde otras bases de datos rechazan un valor que no cabe en la columna, SQLite lo guarda de todos modos. Agrega
STRICTdespués del paréntesis de cierre para que sí lo valide (una tabla estricta solo acepta los tiposINT,INTEGER,REAL,TEXT,BLOByANY).
CREATE TABLE products (
sku VARCHAR(5),
quantity INTEGER
);
-- SQLite stores this row; other databases reject it with an error
INSERT INTO products VALUES ('LAMP-001', 'twelve');
SELECT sku, quantity FROM products;
-- Output (SQLite):
-- sku | quantity
-- ---------+---------
-- LAMP-001 | twelve
-
Declara cada llave foránea en su propia línea
FOREIGN KEY, no comoREFERENCESdentro de la definición de la columna: MySQL 8 acepta esa forma corta y luego la ignora. SQLite solo aplica las llaves foráneas después dePRAGMA foreign_keys = ON;, que tienes que ejecutar en cada conexión. -
CREATE TABLE falla si la tabla ya existe. Escribe
CREATE TABLE IF NOT EXISTSpara omitirla en su lugar. -
En MySQL, una columna
TEXTno puede tenerDEFAULTniUNIQUE. UsaVARCHAR(n), como en los ejemplos de aquí.
Sintaxis alternativa
Los ids autonuméricos se escriben distinto en cada base de datos:
| Base de datos | Columna id autonumérica |
|---|---|
| PostgreSQL | id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY |
| MySQL | id INT AUTO_INCREMENT PRIMARY KEY |
| SQLite | id INTEGER PRIMARY KEY |
| SQL Server | id INT IDENTITY(1,1) PRIMARY KEY |
Si omites el id en un insert, la base de datos pone el siguiente número.
SQL Server también tiene sus propios nombres para columnas de verdadero/falso y de fecha y hora, y no tiene IF NOT EXISTS. Usa BIT (con 1 y 0) en lugar de BOOLEAN, DATETIME2 para fecha y hora (su TIMESTAMP es un número de versión de fila, no una fecha), y revisa OBJECT_ID antes de crear la tabla:
-- SQL Server
IF OBJECT_ID('users', 'U') IS NULL
CREATE TABLE users (
id INT IDENTITY(1,1) PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
is_active BIT NOT NULL DEFAULT 1,
created_at DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
¿Cuándo deberías usar CREATE TABLE?
Toda tabla empieza con CREATE TABLE, pero las columnas y restricciones que elijas resuelven problemas distintos.
Guardar un nuevo tipo de dato
Cada cosa que tu aplicación registra, como clientes, libros o facturas, tiene su propia tabla, con una columna para cada dato sobre ella y un tipo adecuado para sus valores.
Darle a cada fila un ID único
Una PRIMARY KEY evita que dos filas compartan identificador, así siempre puedes encontrar, actualizar o enlazar exactamente una fila. Deja que la base de datos numere las filas (consulta “Sintaxis alternativa” arriba), o combina dos columnas cuando se necesite un par de valores para identificar una fila.
Evitar datos incorrectos o faltantes
Las restricciones rechazan las filas que rompen tus reglas: NOT NULL para columnas obligatorias, UNIQUE para valores como direcciones de correo, y CHECK para rangos permitidos. DEFAULT llena una columna que un insert omite.
Enlazar tablas relacionadas
Una FOREIGN KEY hace que una columna apunte a una fila de otra tabla, para que un pedido no pueda referirse a un cliente que no existe. Agrega ON DELETE CASCADE y, al borrar la fila padre, también se borran las filas que apuntan a ella.
Guardar resultados de consultas como tabla
CREATE TABLE ... AS SELECT crea una tabla y la llena a partir de una consulta en una sola sentencia. Úsalo para snapshots, tablas de reportes o un respaldo de las filas que estás por modificar.
Ejemplos reales de CREATE TABLE
Los mensajes de error son de PostgreSQL. Otras bases de datos rechazan las mismas filas con su propia redacción.
Una tabla de enlace con llave de dos columnas
Los estudiantes toman muchos cursos y los cursos tienen muchos estudiantes. La tabla enrollments los enlaza, y su llave primaria es el par de ids, así un estudiante puede inscribirse en muchos cursos pero no dos veces en el mismo:
CREATE TABLE enrollments (
student_id INTEGER NOT NULL,
course_id INTEGER NOT NULL,
enrolled_on DATE,
PRIMARY KEY (student_id, course_id)
);
INSERT INTO enrollments VALUES (1, 101, '2026-09-01');
INSERT INTO enrollments VALUES (1, 102, '2026-09-01');
INSERT INTO enrollments VALUES (1, 101, '2026-09-08');
-- ERROR: duplicate key value violates unique constraint "enrollments_pkey"
-- DETAIL: Key (student_id, course_id)=(1, 101) already exists.
SELECT * FROM enrollments;
-- Output:
-- student_id | course_id | enrolled_on
-- -----------+-----------+------------
-- 1 | 101 | 2026-09-01
-- 1 | 102 | 2026-09-01
Registros que siguen las reglas
Cada cuenta necesita una dirección de correo que ninguna otra cuenta use y al menos un asiento. Las cuentas nuevas empiezan en el plan gratuito con un asiento:
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
tier VARCHAR(20) NOT NULL DEFAULT 'free',
seats INTEGER NOT NULL DEFAULT 1 CHECK (seats > 0)
);
INSERT INTO accounts (id, email) VALUES (1, 'sam@example.com');
SELECT * FROM accounts;
-- Output:
-- id | email | tier | seats
-- ---+-----------------+------+------
-- 1 | sam@example.com | free | 1
INSERT INTO accounts (id, email) VALUES (2, 'sam@example.com');
-- ERROR: duplicate key value violates unique constraint "accounts_email_key"
INSERT INTO accounts (id, email, seats) VALUES (3, 'kim@example.com', 0);
-- ERROR: new row ... violates check constraint "accounts_seats_check"
INSERT INTO accounts (id) VALUES (4);
-- ERROR: null value in column "email" ... violates not-null constraint
Pedidos que deben pertenecer a un cliente
Cada pedido apunta a un cliente. La llave foránea rechaza un pedido para un cliente que no existe, y ON DELETE CASCADE elimina los pedidos de un cliente cuando se borra al cliente. En SQLite, ejecuta primero PRAGMA foreign_keys = ON;.
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
total DECIMAL(10,2),
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE
);
-- Input: customers
-- id | name
-- ---+-----------
-- 1 | Ana Lima
-- 2 | Ben Okafor
-- Input: orders
-- id | customer_id | total
-- ---+-------------+------
-- 10 | 1 | 25.00
-- 11 | 1 | 60.00
-- 12 | 2 | 42.50
INSERT INTO orders VALUES (13, 99, 15.00);
-- ERROR: ... violates foreign key constraint "orders_customer_id_fkey"
-- DETAIL: Key (customer_id)=(99) is not present in table "customers".
DELETE FROM customers WHERE id = 1;
-- Output (orders after the DELETE):
-- id | customer_id | total
-- ---+-------------+------
-- 12 | 2 | 42.50
Un snapshot de clientes activos
Copia los clientes que hicieron pedidos este año a su propia tabla, para una lista de campaña que no cambie conforme llegan pedidos nuevos:
-- Input: customers
-- customer_id | name | email | last_order_date
-- ------------+------------+-------------------+----------------
-- 1 | Ana Lima | ana@example.com | 2026-03-18
-- 2 | Ben Okafor | ben@example.com | 2025-11-02
-- 3 | Chloe Park | chloe@example.com | 2026-06-30
-- 4 | Dev Shah | dev@example.com | NULL
CREATE TABLE active_customers AS
SELECT customer_id, name, email
FROM customers
WHERE last_order_date >= '2026-01-01';
-- SQL Server has no CREATE TABLE ... AS. Use SELECT ... INTO:
SELECT customer_id, name, email
INTO active_customers
FROM customers
WHERE last_order_date >= '2026-01-01';
-- Output (active_customers):
-- customer_id | name | email
-- ------------+------------+------------------
-- 1 | Ana Lima | ana@example.com
-- 3 | Chloe Park | chloe@example.com
La tabla nueva recibe las columnas, sus tipos y las filas, pero no la llave primaria ni ninguna otra restricción. Agrégalas con ALTER TABLE si las necesitas.
Más lecturas sobre CREATE TABLE
En este blog:
- Guía de tablas temporales en SQL: tablas que solo duran lo que dura tu sesión
- SQL ALTER TABLE add column: cómo cambiar una tabla después de crearla
- Llaves primarias compuestas en SQL: llaves formadas por más de una columna
- Cómo usar llaves foráneas en PostgreSQL: llaves foráneas y sus acciones de borrado a fondo
- Guía de relaciones en bases de datos: cómo diseñar tablas que se enlazan entre sí
- Sentencia SQL INSERT: cómo agregar filas a una tabla nueva
- Creador de tablas SQL: arma una sentencia CREATE TABLE en tu navegador en lugar de escribirla a mano
Documentación oficial:
Beekeeper Studio es un cliente de bases de datos gratuito y de código abierto
La mejor herramienta de consultas y edición de SQL que he usado. Tiene todo lo que necesito para administrar mi base de datos. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio es rápido, intuitivo y fácil de usar. Es compatible con muchísimas bases de datos y funciona de maravilla en Windows, Mac y Linux.
Lo que dicen los usuarios de Beekeeper Studio
"Beekeeper Studio reemplazó por completo mi antiguo flujo de trabajo con SQL. Es rápido, intuitivo y hace que trabajar con bases de datos vuelva a ser agradable."
"He probado muchas GUI de bases de datos, pero Beekeeper logra el equilibrio perfecto entre funciones y simplicidad. Simplemente funciona."