En esta página

El modelo relacional

14 min lectura TextoCap. 1 — Fundamentos de bases de datos

El modelo relacional

El modelo relacional es el fundamento matemático sobre el que descansa SQL. Fue concebido por Edgar F. Codd en 1970 basándose en la teoría de conjuntos y el álgebra relacional. Entender este modelo no es solo teoría académica: es lo que te permite diseñar bases de datos que no se corrompan, que sean fáciles de consultar y que escalen correctamente.

Tablas, filas y columnas

En el modelo relacional, todos los datos se organizan en relaciones, que en la práctica llamamos tablas. Una tabla tiene tres componentes principales:

  • Columnas (atributos): definen la estructura. Cada columna tiene un nombre y un tipo de dato. Son equivalentes a los campos de un formulario.
  • Filas (tuplas): cada fila es un registro concreto, una instancia de la entidad que representa la tabla.
  • Cabecera: el conjunto de columnas con sus tipos. Define el "esquema" de la tabla.

Una propiedad fundamental: el orden de las filas no importa. A diferencia de un array en programación, no puedes asumir que los registros están en algún orden particular a menos que lo especifiques explícitamente con ORDER BY.

-- Una tabla de usuarios tiene esta estructura
CREATE TABLE usuarios (
  id          SERIAL PRIMARY KEY,
  email       VARCHAR(255) NOT NULL UNIQUE,
  nombre      VARCHAR(100) NOT NULL,
  apellido    VARCHAR(100),
  activo      BOOLEAN      NOT NULL DEFAULT true,
  creado_en   TIMESTAMP    NOT NULL DEFAULT NOW()
);

-- Cada fila es un usuario concreto
INSERT INTO usuarios (email, nombre, apellido)
VALUES
  ('[email protected]',   'Ana',    'García'),
  ('[email protected]',  'Luis',   'Martínez'),
  ('[email protected]',   'Eva',    'López');

-- Consultamos la tabla
SELECT * FROM usuarios;

Claves primarias (Primary Keys)

La clave primaria es el identificador único de cada fila en una tabla. Sus propiedades son:

  1. Unicidad: no pueden existir dos filas con el mismo valor de clave primaria.
  2. No nulidad: la clave primaria nunca puede ser NULL.
  3. Estabilidad: idealmente, el valor de la clave primaria no debería cambiar nunca.

Existen dos grandes estrategias para las claves primarias:

Claves surrogadas (recomendadas)

Son identificadores artificiales sin significado de negocio, generados automáticamente por la base de datos:

-- SERIAL: entero autoincremental (equivale a SEQUENCE + DEFAULT)
CREATE TABLE productos (
  id SERIAL PRIMARY KEY,
  nombre VARCHAR(200) NOT NULL
);

-- UUID v4: identificador universalmente único (mejor para sistemas distribuidos)
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

CREATE TABLE pedidos (
  id    UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  total NUMERIC(10,2) NOT NULL
);

-- En PostgreSQL 18, también puedes usar gen_random_uuid() sin extensión
-- ya que está disponible en el módulo pg_catalog

Claves naturales

Son atributos del mundo real que identifican unívocamente una entidad: el DNI de una persona, el ISBN de un libro, el código IBAN de una cuenta bancaria.

El problema con las claves naturales es que el mundo real cambia: una persona puede cambiar su DNI, un producto puede cambiar su código de barras. Por eso, en la mayoría de casos se prefieren las claves surrogadas.

Claves foráneas (Foreign Keys)

Las claves foráneas son el mecanismo que implementa las relaciones entre tablas. Una clave foránea en la tabla A referencia la clave primaria de la tabla B, estableciendo un vínculo entre ambas.

CREATE TABLE categorias (
  id     SERIAL PRIMARY KEY,
  nombre VARCHAR(100) NOT NULL UNIQUE
);

CREATE TABLE productos (
  id           SERIAL PRIMARY KEY,
  nombre       VARCHAR(200) NOT NULL,
  precio       NUMERIC(10,2) NOT NULL,
  categoria_id INTEGER NOT NULL REFERENCES categorias(id)
    ON DELETE RESTRICT
    ON UPDATE CASCADE
);

-- La clave foránea garantiza integridad referencial:
-- No puedes insertar un producto con categoria_id=99 si no existe esa categoría
INSERT INTO categorias (nombre) VALUES ('Electrónica'), ('Ropa'), ('Libros');

INSERT INTO productos (nombre, precio, categoria_id)
VALUES ('Laptop Pro', 1299.99, 1);  -- Referencia a 'Electrónica'

-- Esto fallaría con un error de restricción de clave foránea:
-- INSERT INTO productos (nombre, precio, categoria_id) VALUES ('X', 10, 999);

Tipos de relaciones

Las relaciones entre entidades se clasifican según la cardinalidad: cuántas instancias de una entidad pueden estar relacionadas con instancias de la otra.

Relación uno a uno (1:1)

Una fila de la tabla A está relacionada con exactamente una fila de la tabla B, y viceversa. Este tipo de relación es poco común y a menudo indica que las tablas deberían fusionarse, aunque hay casos válidos:

-- Separar datos sensibles en una tabla aparte (ej: información de pago)
CREATE TABLE usuarios (
  id    SERIAL PRIMARY KEY,
  email VARCHAR(255) NOT NULL UNIQUE,
  nombre VARCHAR(100) NOT NULL
);

CREATE TABLE perfiles_pago (
  usuario_id      INTEGER PRIMARY KEY REFERENCES usuarios(id) ON DELETE CASCADE,
  numero_tarjeta  VARCHAR(20),  -- En producción: encriptado
  fecha_expiracion DATE
);
-- La clave primaria de perfiles_pago ES TAMBIÉN la clave foránea (truco para 1:1)

Relación uno a muchos (1:N)

La más común. Un registro de la tabla A puede estar relacionado con múltiples registros de la tabla B, pero cada registro de B pertenece a un solo registro de A.

-- Un cliente puede tener muchos pedidos
-- pero cada pedido pertenece a un solo cliente
CREATE TABLE clientes (
  id     SERIAL PRIMARY KEY,
  nombre VARCHAR(150) NOT NULL,
  email  VARCHAR(255) NOT NULL UNIQUE
);

CREATE TABLE pedidos (
  id          SERIAL PRIMARY KEY,
  cliente_id  INTEGER NOT NULL REFERENCES clientes(id),
  total       NUMERIC(10,2) NOT NULL,
  estado      VARCHAR(20) NOT NULL DEFAULT 'pendiente',
  creado_en   TIMESTAMP NOT NULL DEFAULT NOW()
);

Relación muchos a muchos (N:M)

Múltiples registros de A pueden relacionarse con múltiples registros de B. Para implementarla, se necesita una tabla intermedia (junction table o tabla de unión):

-- Un pedido puede tener muchos productos
-- y un producto puede aparecer en muchos pedidos
CREATE TABLE pedidos_productos (
  pedido_id   INTEGER NOT NULL REFERENCES pedidos(id) ON DELETE CASCADE,
  producto_id INTEGER NOT NULL REFERENCES productos(id) ON DELETE RESTRICT,
  cantidad    INTEGER NOT NULL DEFAULT 1 CHECK (cantidad > 0),
  precio_unit NUMERIC(10,2) NOT NULL,  -- Precio al momento de la compra
  PRIMARY KEY (pedido_id, producto_id)  -- Clave primaria compuesta
);

La tabla intermedia puede tener sus propios atributos (como cantidad y precio_unit), lo que la convierte en una entidad con información propia.

Diagramas Entidad-Relación (ER)

Los diagramas ER son la herramienta estándar para visualizar el modelo de datos antes de implementarlo. Usan una notación gráfica para representar:

  • Entidades: rectángulos (→ tablas)
  • Atributos: óvalos o columnas dentro del rectángulo (→ columnas)
  • Relaciones: rombos o líneas con anotaciones de cardinalidad
  • Cardinalidad: la notación "crow's foot" (pata de gallo) es la más usada en herramientas modernas

Notación crow's foot:

  • | = exactamente uno
  • o = cero o uno (opcional)
  • < = muchos (cero o más)
  • |< = uno o más

La notación se lee en ambas direcciones: "un cliente tiene cero o más pedidos" y "un pedido pertenece a exactamente un cliente".

Esquemas en PostgreSQL

Un esquema es un espacio de nombres que organiza objetos de base de datos (tablas, vistas, funciones) dentro de una base de datos. Por defecto, todo va al esquema public.

-- Crear esquemas para organizar el modelo
CREATE SCHEMA tienda;
CREATE SCHEMA reportes;

-- Crear tablas en un esquema específico
CREATE TABLE tienda.productos (
  id     SERIAL PRIMARY KEY,
  nombre VARCHAR(200) NOT NULL
);

CREATE TABLE tienda.inventario (
  producto_id INTEGER PRIMARY KEY REFERENCES tienda.productos(id),
  cantidad    INTEGER NOT NULL DEFAULT 0 CHECK (cantidad >= 0)
);

-- Ver todos los esquemas
SELECT schema_name FROM information_schema.schemata;

-- El search_path determina qué esquema se usa por defecto
SET search_path TO tienda, public;

-- Ahora puedes referenciar las tablas sin prefijo de esquema
SELECT * FROM productos;  -- Busca primero en 'tienda', luego en 'public'

Integridad de datos

El modelo relacional garantiza la integridad de los datos a través de varios mecanismos:

Integridad de entidad: la clave primaria no puede ser NULL. Cada fila debe ser identificable de forma única.

Integridad referencial: una clave foránea debe referenciar un valor que existe en la tabla referenciada, o ser NULL si la relación es opcional.

Integridad de dominio: los valores de cada columna deben pertenecer al dominio (tipo) definido. Un INTEGER no puede contener texto.

Integridad definida por el usuario: restricciones adicionales definidas con CHECK, UNIQUE, NOT NULL y triggers.

[!warning] ¡No pongas lógica de negocio en la aplicación que debería estar en la base de datos! Si una regla de integridad (como "el precio debe ser positivo") se implementa solo en el código de la aplicación, cualquier acceso directo a la base de datos podría violarla. Las restricciones CHECK, NOT NULL y las claves foráneas son tu primera línea de defensa.

Normalización: una vista previa

El proceso de normalización es el conjunto de reglas que te guían para diseñar tablas sin redundancias innecesarias. Lo exploraremos en detalle en la lección 10, pero el principio básico es: cada dato debe guardarse en un solo lugar.

Si el nombre de una ciudad aparece en 10.000 filas de clientes, y esa ciudad cambia de nombre (o descubres que tenías un error tipográfico), tendrás que actualizar 10.000 filas. Si en cambio tienes una tabla de ciudades con una clave foránea, basta con actualizar una sola fila.

[!tip] Herramientas para diagramas ER: dbdiagram.io (gratis, basado en código), pgAdmin (incluido con PostgreSQL, genera diagramas automáticamente desde esquemas existentes), Lucidchart y draw.io para diagramas más elaborados. En equipos profesionales, tener el diagrama ER actualizado es tan importante como tener el código documentado.

Conclusión

El modelo relacional es elegante en su simplicidad: todo son tablas, todas las operaciones producen tablas, y las relaciones se expresan mediante valores compartidos. Esta consistencia matemática es lo que hace que SQL sea tan poderoso y expresivo después de más de 50 años.

En la siguiente lección instalaremos PostgreSQL 18, exploraremos las herramientas disponibles (psql, pgAdmin) y crearemos nuestras primeras tablas reales.


nextSteps:

  • slug: configurar-postgresql label: "Siguiente: Configurar PostgreSQL"