PRIMARY KEY

La restricción PRIMARY KEY identifica de forma única cada fila de una tabla. Una clave primaria combina dos propiedades: los valores deben ser únicos (no pueden repetirse) y no pueden ser nulos. Cada tabla solo puede tener una clave primaria, aunque esa clave puede estar formada por una o varias columnas.

Sintaxis

Como restricción de columna:

CREATE TABLE nombre_tabla (
    id INT PRIMARY KEY
);

Como restricción de tabla:

CREATE TABLE nombre_tabla (
    id INT,
    PRIMARY KEY (id)
);

Clave primaria simple

La forma más común es un entero con AUTO_INCREMENT:

CREATE TABLE categorias_demo (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL
);
 
INSERT INTO categorias_demo (nombre) VALUES
('Electrónica'),
('Ropa'),
('Hogar');
SELECT * FROM categorias_demo;
idnombre
1Electrónica
2Ropa
3Hogar

MySQL asigna automáticamente los valores 1, 2, 3 a la columna id. Cada valor es único y no nulo, garantizado por la restricción PRIMARY KEY.

Unicidad

La clave primaria rechaza valores duplicados:

INSERT INTO categorias_demo (id, nombre) VALUES (1, 'Deportes');
ERROR 1062 (23000): Duplicate entry '1' for key 'categorias_demo.PRIMARY'

El valor 1 ya existe en id, por lo que la inserción falla. Esto garantiza que cada fila sea identificable de forma inequívoca.

NOT NULL implícito

La clave primaria no admite valores nulos:

INSERT INTO categorias_demo (id, nombre) VALUES (NULL, 'Deportes');

Con AUTO_INCREMENT, NULL se interpreta como "genera el siguiente valor automáticamente", por lo que funciona. Pero en una clave primaria sin AUTO_INCREMENT:

CREATE TABLE sin_auto (
    codigo VARCHAR(10) PRIMARY KEY,
    nombre VARCHAR(100)
);
 
INSERT INTO sin_auto (codigo, nombre) VALUES (NULL, 'Test');
ERROR 1048 (23000): Column 'codigo' cannot be null

Clave primaria compuesta

Cuando ninguna columna individual identifica una fila de forma única, puedes usar una clave primaria formada por varias columnas:

CREATE TABLE inscripciones (
    estudiante_id INT,
    curso_id INT,
    fecha DATE NOT NULL,
    nota DECIMAL(4, 2),
    PRIMARY KEY (estudiante_id, curso_id)
);

La clave primaria compuesta debe definirse como restricción de tabla, no puede ir en la definición de una columna individual.

INSERT INTO inscripciones VALUES (1, 100, '2025-09-01', NULL);
INSERT INTO inscripciones VALUES (1, 101, '2025-09-01', NULL);  -- OK: mismo estudiante, curso diferente
INSERT INTO inscripciones VALUES (2, 100, '2025-09-01', NULL);  -- OK: estudiante diferente, mismo curso
INSERT INTO inscripciones VALUES (1, 100, '2025-10-01', 8.5);   -- ERROR: combinación duplicada
ERROR 1062 (23000): Duplicate entry '1-100' for key 'inscripciones.PRIMARY'

La combinación (1, 100) ya existe. La clave primaria compuesta rechaza duplicados de la combinación completa, no de columnas individuales.

Clave primaria en nuestra base de datos

Veamos las claves primarias de tienda_mysql. La tabla detalle_pedidos podría haber usado una clave compuesta (pedido_id, producto_id), pero utiliza un id simple porque un pedido podría contener el mismo producto más de una vez (en implementaciones más complejas):

SELECT
    TABLE_NAME,
    COLUMN_NAME,
    ORDINAL_POSITION
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = 'tienda_mysql'
  AND CONSTRAINT_NAME = 'PRIMARY'
ORDER BY TABLE_NAME, ORDINAL_POSITION;
TABLE_NAMECOLUMN_NAMEORDINAL_POSITION
categoriasid1
clientesid1
detalle_pedidosid1
empleadosid1
etiquetas_productoid1
pedidosid1
productosid1
resenasid1

Todas las tablas usan id como clave primaria simple. Un ejemplo de clave compuesta en nuestro esquema es la restricción UNIQUE de etiquetas_producto sobre (producto_id, etiqueta), que funciona conceptualmente como una clave alternativa.

Añadir clave primaria a tabla existente

Si creaste una tabla sin clave primaria, puedes añadirla después:

CREATE TABLE logs_sin_pk (
    timestamp DATETIME,
    mensaje TEXT
);
 
ALTER TABLE logs_sin_pk
    ADD COLUMN id INT AUTO_INCREMENT PRIMARY KEY FIRST;

MySQL asigna valores secuenciales a las filas existentes. Si la tabla tiene filas con valores duplicados o nulos en la columna designada, la operación falla.

Eliminar clave primaria

-- Primero quitar AUTO_INCREMENT si existe
ALTER TABLE logs_sin_pk
    MODIFY COLUMN id INT;
 
-- Después eliminar la clave primaria
ALTER TABLE logs_sin_pk
    DROP PRIMARY KEY;

No puedes eliminar la clave primaria de una columna AUTO_INCREMENT directamente. Debes quitar el AUTO_INCREMENT primero.

Clave primaria con VARCHAR

Aunque lo más común es usar enteros, puedes usar VARCHAR como clave primaria:

CREATE TABLE paises (
    codigo CHAR(2) PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL
);
 
INSERT INTO paises VALUES
('ES', 'España'),
('MX', 'México'),
('AR', 'Argentina'),
('CO', 'Colombia');

Los códigos ISO de país son un buen ejemplo de clave primaria natural: son únicos, cortos y estables. Sin embargo, las claves primarias de texto son más lentas para JOINs y ocupan más espacio en índices que los enteros.

Clave primaria natural vs artificial

Una clave natural usa datos del dominio (email, DNI, código de país). Una clave artificial (o surrogate) es un valor generado sin significado de negocio (un autoincremento o UUID).

Claves naturales como el email parecen buenas candidatas, pero pueden cambiar (un usuario cambia de email) y eso afecta a todas las claves foráneas. Los enteros autoincrementados son simples, eficientes y estables. Por eso la mayoría de las tablas en tienda_mysql usan id INT AUTO_INCREMENT.

UUID como clave primaria

Para sistemas distribuidos donde varios servidores generan IDs simultáneamente, los UUID evitan colisiones:

CREATE TABLE sesiones (
    id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID())),
    usuario_id INT NOT NULL,
    creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
 
INSERT INTO sesiones (usuario_id) VALUES (1);
INSERT INTO sesiones (usuario_id) VALUES (2);
 
SELECT BIN_TO_UUID(id) AS id, usuario_id FROM sesiones;

UUID_TO_BIN convierte el UUID de 36 caracteres a 16 bytes binarios, que es más eficiente que almacenar el UUID como texto. Sin embargo, los UUID tienen peor rendimiento que los enteros secuenciales porque causan más fragmentación en el índice.

Buenas prácticas

Toda tabla debe tener una clave primaria. MySQL funciona mejor con claves primarias porque InnoDB organiza físicamente los datos según la clave primaria (índice clustered).

Prefiere enteros autoincrementados (INT AUTO_INCREMENT o BIGINT AUTO_INCREMENT) para la mayoría de tablas. Son compactos, eficientes y simples.

Usa claves compuestas solo en tablas de relación (muchos-a-muchos) donde la combinación de dos claves foráneas es la identidad natural de la fila.

Evita claves primarias que puedan cambiar. Si eliges un dato de negocio como clave primaria, asegúrate de que sea verdaderamente inmutable.

Limpieza

DROP TABLE IF EXISTS categorias_demo;
DROP TABLE IF EXISTS sin_auto;
DROP TABLE IF EXISTS inscripciones;
DROP TABLE IF EXISTS logs_sin_pk;
DROP TABLE IF EXISTS paises;
DROP TABLE IF EXISTS sesiones;

En el siguiente artículo veremos la restricción FOREIGN KEY, que establece relaciones entre tablas.

Escrito por Eduardo Lázaro