En la lección 01-01 usamos palabras como tabla, fila, columna, clave primaria y clave ajena de manera deliberadamente informal: nos servían para diagnosticar la hoja de cálculo de BiblioRed sin tener que definir nada con rigor. Ahora toca hacerlo bien. El modelo relacional no es "una forma bonita de organizar tablas": es una teoría matemática, publicada por Edgar F. Codd en 1970, y esa base formal es exactamente la razón de que los sistemas relacionales lleven medio siglo sin ser desplazados.

Entender el modelo tiene una consecuencia muy práctica. Cuando dentro de dos lecciones escribas un JOIN y no devuelva lo que esperabas, o cuando una comparación con NULL no filtre ninguna fila, la explicación no estará en el manual de PostgreSQL: estará en la teoría que veremos hoy. Esta es la última lección sin teclear (casi: hay SQL de ilustración, pero no lo ejecutarás todavía). Al final tendrás el plano completo del esquema de BiblioRed, que en la lección siguiente convertiremos en tablas reales dentro de biblioredb.

Contenido

  1. Relación, tupla, atributo y dominio
  2. Grado y cardinalidad
  3. Por qué una relación es un conjunto
  4. Relación frente a hoja de cálculo
  5. La familia de las claves: superclave, candidata, primaria, alternativa
  6. Claves ajenas y el vínculo entre relaciones
  7. Clave natural frente a clave subrogada: el caso del ISBN
  8. Las tres reglas de integridad del modelo
  9. El valor NULL y la lógica de tres valores
  10. Introducción al álgebra relacional
  11. El esquema conceptual de BiblioRed
  12. Errores comunes y consejos
  13. Ejercicios
  14. Conclusión

  1. Relación, tupla, atributo y dominio

El modelo relacional se construye sobre cuatro conceptos. Los presentamos con su nombre formal y con su nombre coloquial, porque en el trabajo diario oirás los dos.

Nombre formal Nombre coloquial (SQL) Qué es
Relación Tabla Un conjunto de tuplas que comparten la misma estructura
Tupla Fila o registro Un elemento de la relación: los datos de un socio, un libro
Atributo Columna o campo Una propiedad con nombre, presente en todas las tuplas
Dominio Tipo de dato El conjunto de valores válidos para un atributo

Cuidado con una confusión muy extendida: "relación" no significa "vínculo entre tablas". En el modelo relacional, una relación es una tabla. El vínculo entre tablas se llama clave ajena (o, en diseño, interrelación). Que el modelo se llame "relacional" no viene de que las tablas se relacionen entre sí, sino de que cada tabla es, matemáticamente, una relación en el sentido de la teoría de conjuntos: un subconjunto del producto cartesiano de sus dominios.

Veámoslo con la relación socios de BiblioRed:

socio_id nombre apellidos email fecha_alta sucursal_id
14 Marta Alsina [email protected] 2021-03-08 2
15 Iván Pereda [email protected] 2021-09-19 2
16 Nuria Bastos [email protected] 2022-01-30 1
  • La relación es socios.
  • Cada una de las tres líneas es una tupla.
  • nombre, email, fecha_alta… son atributos.
  • El dominio de fecha_alta es "las fechas válidas del calendario"; el de socio_id, "los enteros positivos"; el de email, "cadenas de hasta 120 caracteres". El dominio es lo que impide que en fecha_alta aparezca "el martes pasado".

Esquema e instancia, otra vez

En 01-01 distinguimos esquema (la estructura) de instancia (los datos de un momento concreto). Formalmente:

  • El esquema de la relación se escribe socios(socio_id, nombre, apellidos, email, fecha_alta, sucursal_id). Es estable: cambia solo cuando el diseñador lo cambia.
  • La instancia o extensión es el conjunto concreto de tuplas que hay ahora mismo. Cambia con cada préstamo, cada alta y cada baja.

Cuando hablamos de "la tabla socios" casi siempre nos referimos al esquema; cuando decimos "hay 12.000 socios", a la instancia.

  1. Grado y cardinalidad

Dos medidas elementales de una relación:

  • Grado (o aridad): el número de atributos. La relación socios del ejemplo tiene grado 6. El grado es una propiedad del esquema.
  • Cardinalidad: el número de tuplas. En el ejemplo, 3; en BiblioRed de verdad, 12.000. La cardinalidad es una propiedad de la instancia.

Una regla mnemotécnica: el grado se cuenta a lo ancho y casi nunca cambia; la cardinalidad se cuenta a lo alto y cambia todo el rato.

Casos límite que conviene tener claros:

  • Una relación de cardinalidad 0 (sin tuplas) es perfectamente válida: es exactamente lo que tenemos ahora en biblioredb, donde las tablas ni siquiera existen todavía, y lo que tendremos tras crearlas en la lección siguiente.
  • Una relación de grado 0 es una curiosidad matemática sin utilidad práctica; SQL no la admite.

  1. Por qué una relación es un conjunto

Aquí está la idea que más consecuencias tiene. Una relación es un conjunto de tuplas, y los conjuntos matemáticos tienen dos propiedades que las hojas de cálculo no tienen:

No hay orden

En un conjunto, {a, b, c} y {c, a, b} son el mismo conjunto. Por tanto, las filas de una tabla no tienen orden intrínseco. Tampoco lo tienen las columnas, aunque en SQL se declaran en una secuencia.

La consecuencia práctica es contundente: si ejecutas una consulta sin ORDER BY, el gestor puede devolverte las filas en cualquier orden, y ese orden puede cambiar entre dos ejecuciones idénticas sin que nadie haya tocado nada. No es un fallo: es el modelo. Si el orden importa, hay que pedirlo explícitamente (lo veremos en 02-03).

No hay duplicados

En un conjunto, un elemento está o no está; no puede estar "dos veces". Por tanto, en una relación no puede haber dos tuplas idénticas. Esta propiedad es la que justifica la existencia obligatoria de una clave primaria: siempre debe haber algo que distinga una tupla de otra.

La letra pequeña: SQL no es tan estricto

Honestidad intelectual: SQL no implementa el modelo relacional puro. Una tabla SQL es técnicamente un multiconjunto (bag), no un conjunto: si no declaras una clave primaria ni una restricción de unicidad, SQL te dejará insertar dos filas idénticas y ambas convivirán.

-- Legal en SQL si la tabla no tiene clave primaria.
-- Prohibido en el modelo relacional puro.
INSERT INTO socios_sin_clave VALUES ('Marta', 'Alsina');
INSERT INTO socios_sin_clave VALUES ('Marta', 'Alsina');
-- Resultado: dos filas indistinguibles, imposibles de borrar por separado

Por eso una de las primeras reglas prácticas del curso es: toda tabla lleva clave primaria. No es burocracia; es lo que devuelve a la tabla su condición de relación.

  1. Relación frente a hoja de cálculo

La hoja de cálculo de BiblioRed que diagnosticamos en 01-01 se parecía mucho a una tabla. Estas son las diferencias que la hacían fallar:

Aspecto Relación (modelo relacional) Hoja de cálculo
Orden de las filas No existe; se pide con ORDER BY Es intrínseco: la fila 7 está entre la 6 y la 8
Duplicados Prohibidos (clave primaria) Permitidos y frecuentes
Dominio de una columna Fijo y verificado por el gestor Cada celda puede tener el tipo que quiera
Celdas vacías NULL, con semántica definida Vacío ambiguo: ¿cero, texto vacío, no aplica?
Identificación de una fila Por el valor de su clave Por su posición (A7)
Referencias entre datos Claves ajenas verificadas Fórmulas frágiles que se rompen al insertar filas
Acceso simultáneo Controlado por el gestor Un usuario a la vez, o conflictos de versión

La diferencia decisiva es la penúltima línea. En una hoja de cálculo, una fila se identifica por dónde está; en una relación, por lo que vale. Por eso insertar una fila en medio de una hoja rompe fórmulas, y por eso en una base de datos no rompe nada: nadie depende de la posición.

  1. La familia de las claves: superclave, candidata, primaria, alternativa

Para garantizar que no hay tuplas duplicadas necesitamos identificar cada tupla. El modelo define una jerarquía precisa de conceptos. Trabajaremos sobre la relación libros de BiblioRed:

libro_id isbn titulo autor_id editorial anio_publicacion
331 9788401339097 El mapa del tiempo 1 Editorial Andana 2008
332 9788401337208 Los pilares de la Tierra 2 Editorial Andana 1989
333 9788412007701 La casa de las mareas 3 Ediciones Marlia 2015

Superclave

Un conjunto de atributos que identifica unívocamente cada tupla: no puede haber dos tuplas con los mismos valores en todos ellos.

En libros son superclaves, entre otras:

  • {libro_id}
  • {isbn}
  • {libro_id, titulo}
  • {isbn, editorial, anio_publicacion}
  • El conjunto de todos los atributos (siempre es superclave, porque no hay tuplas duplicadas)

Fíjate en que a una superclave le puedes añadir atributos irrelevantes y sigue siendo superclave. Por eso hace falta afinar.

Clave candidata

Una superclave mínima: si le quitas cualquier atributo, deja de identificar unívocamente. {libro_id, titulo} no es candidata, porque {libro_id} ya basta por sí solo. En libros las claves candidatas son:

  • {libro_id}
  • {isbn}

Una relación puede tener varias claves candidatas, y siempre tiene al menos una.

Clave primaria

La clave candidata que el diseñador elige como identificador oficial. Es la que usarán las claves ajenas de otras tablas y la que el gestor emplea para organizar el almacenamiento. En libros elegiremos libro_id (en el apartado 7 justificamos por qué).

Clave alternativa

Las claves candidatas no elegidas. En libros, isbn es clave alternativa. En SQL se declaran con UNIQUE, y siguen siendo tan obligatorias de respetar como la primaria: si dejas que dos libros compartan ISBN, el catálogo de BiblioRed se corrompe igual.

Clave compuesta

Una clave (candidata o primaria) formada por más de un atributo. Si BiblioRed tuviera una tabla libros_autores para libros escritos a varias manos, su clave primaria natural sería {libro_id, autor_id}: ni el libro solo ni el autor solo bastan, pero la pareja sí.

flowchart TD
    A["Todos los conjuntos de atributos"] --> B["Superclaves<br/>identifican unívocamente"]
    B --> C["Claves candidatas<br/>superclaves mínimas"]
    C --> D["Clave primaria<br/>la candidata elegida"]
    C --> E["Claves alternativas<br/>las candidatas no elegidas<br/>(UNIQUE en SQL)"]

  1. Claves ajenas y el vínculo entre relaciones

Una clave ajena (foreign key) es un atributo, o conjunto de atributos, de una relación cuyos valores deben coincidir con los de la clave primaria de otra relación (o de la misma).

En BiblioRed:

  • socios.sucursal_id es clave ajena hacia sucursales.sucursal_id: cada socio pertenece a una sucursal existente.
  • ejemplares.libro_id es clave ajena hacia libros.libro_id: cada ejemplar físico es una copia de un libro del catálogo.
  • prestamos.socio_id y prestamos.ejemplar_id son dos claves ajenas en la misma tabla: un préstamo conecta un socio con un ejemplar.

Vocabulario: la tabla que contiene la clave ajena es la hija o referenciante; la que contiene la clave primaria apuntada es la padre o referenciada.

Dos observaciones importantes:

  1. Una clave ajena puede admitir NULL (salvo que se declare NOT NULL), y ese NULL significa "esta fila no apunta a nadie". Si permitiéramos ejemplares.sucursal_id nulo, estaríamos diciendo que hay ejemplares sin sucursal asignada. En BiblioRed no queremos eso, así que será NOT NULL.
  2. Una clave ajena puede repetirse. Que sucursal_id valga 2 en cientos de socios es exactamente lo esperado: es una relación uno-a-muchos.

El tratamiento práctico de las claves ajenas —qué pasa cuando borras la fila padre, ON DELETE CASCADE, RESTRICT, restricciones diferibles— es el contenido completo de la lección 02-06. Aquí nos quedamos en el concepto.

  1. Clave natural frente a clave subrogada: el caso del ISBN

Este es un debate real de diseño, y BiblioRed lo tiene delante.

  • Una clave natural es un identificador que ya existe en el mundo real y que hemos adoptado como clave: el ISBN de un libro, el NIF de una persona, el código IATA de un aeropuerto.
  • Una clave subrogada (o artificial) es un número que inventa la propia base de datos, sin significado fuera de ella: libro_id = 331.

¿Debería libros tener como clave primaria el isbn (natural) o un libro_id (subrogada)? Comparemos:

Criterio Clave natural (isbn) Clave subrogada (libro_id)
Significado Tiene sentido fuera de la BD Ninguno; solo sirve dentro
Estabilidad Puede cambiar o corregirse (ISBN-10 → ISBN-13, erratas de catalogación) Nunca cambia
Tamaño 13 caracteres, replicados en cada clave ajena 4 bytes de entero
Legibilidad al depurar Alta: ves el ISBN y sabes qué libro es Baja: 331 no dice nada
Universalidad No todos los ítems lo tienen: revistas, folletos, donaciones antiguas Siempre existe
Riesgo de duplicados Real: reediciones mal catalogadas comparten ISBN por error Nulo

Decisión para BiblioRed: clave primaria subrogada libro_id, y isbn como clave alternativa UNIQUE. Los tres motivos que pesan más:

  1. No todo lo que presta BiblioRed tiene ISBN. Fondos anteriores a 1970, publicaciones municipales y donaciones sin catalogar quedarían sin clave. Y una clave primaria no admite NULL (lo veremos en el apartado siguiente).
  2. El ISBN se corrige. Cuando un bibliotecario detecta que se tecleó mal un ISBN y lo arregla, con clave natural habría que propagar el cambio a todas las tablas hijas; con clave subrogada, se corrige un único valor y nadie más se entera.
  3. Las claves ajenas se abaratan. ejemplares tiene 40.000 filas: guardar en cada una un entero de 4 bytes en lugar de una cadena de 13 caracteres reduce el tamaño de la tabla y de sus índices.

Lo que no hacemos es renunciar al ISBN: sigue declarado UNIQUE, de modo que sigue siendo imposible catalogar dos veces el mismo libro. Elegir clave subrogada no es excusa para perder las restricciones del mundo real; ese es el error clásico.

El mismo razonamiento se aplica a ejemplares: la etiqueta física EJ-3081 que lleva pegada el ejemplar es una clave natural excelente para el mostrador, pero la guardaremos en una columna codigo con UNIQUE, y la clave primaria será el entero ejemplar_id.

  1. Las tres reglas de integridad del modelo

El modelo relacional define tres reglas que todo sistema debe hacer cumplir. Se llaman reglas de integridad porque su función es impedir que la base de datos entre en un estado imposible.

Integridad de dominio

Todo valor de un atributo debe pertenecer a su dominio.

Es la regla más elemental y la que más trabajo ahorra. Si el dominio de fecha_prestamo son las fechas, el gestor rechaza 'ayer', '32/13/2026' y '-1'. Si el dominio de anio_publicacion son los enteros, rechaza 'mil novecientos ochenta y nueve'.

En SQL, la integridad de dominio se expresa con los tipos de datos (los veremos operativamente en 02-02) y se refina con restricciones CHECK y NOT NULL (catálogo completo en 04-04).

En la hoja de cálculo de BiblioRed no había integridad de dominio: por eso convivían 2026-06-02, 02/06/26 y pendiente en la misma columna de fechas.

Integridad de entidad

Ningún atributo de la clave primaria puede ser NULL.

El razonamiento es directo: la clave primaria sirve para identificar la tupla. Si su valor es desconocido, la tupla no es identificable, y entonces no puede formar parte de una relación (recuerda: sin duplicados, y dos tuplas con clave desconocida no se pueden distinguir).

De aquí sale la consecuencia práctica del apartado anterior: como no todos los ítems de BiblioRed tienen ISBN, el ISBN no puede ser clave primaria, porque tendría que admitir NULL.

En SQL, esta regla es automática: declarar PRIMARY KEY implica NOT NULL aunque no lo escribas.

Integridad referencial

Todo valor no nulo de una clave ajena debe corresponderse con un valor existente de la clave primaria referenciada.

Enunciada así de simple, prohíbe las filas huérfanas: un préstamo cuyo socio_id sea 9999 cuando no existe el socio 9999; un ejemplar de un libro que no está en el catálogo. En la hoja de cálculo de BiblioRed las había a montones, porque nada impedía teclear un número de socio inventado.

Cómo se declara, qué comprueba el gestor en cada operación y qué hacer cuando borras la fila padre es el contenido íntegro de la lección 02-06. Aquí basta con retener el enunciado.

  1. El valor NULL y la lógica de tres valores

NULL no es cero. NULL no es la cadena vacía. NULL no es "falso". NULL es la ausencia de valor, y admite al menos tres lecturas distintas que el modelo no distingue:

  • Desconocido: el socio 19, Pau Miralles, tiene correo pero no lo dio al darse de alta.
  • No aplicable: fecha_devolucion de un préstamo todavía abierto — el libro no se ha devuelto, así que no hay fecha que poner.
  • Pendiente: aún no se ha registrado.

En BiblioRed usaremos fecha_devolucion IS NULL como definición operativa de "préstamo abierto". Es un uso limpio y muy común: la ausencia de fecha significa algo.

La lógica de tres valores

Como NULL significa "no sé", cualquier comparación con NULL da como resultado… no sé. SQL formaliza esto con una lógica de tres valores: VERDADERO, FALSO y DESCONOCIDO.

Expresión Resultado
5 = 5 VERDADERO
5 = 3 FALSO
5 = NULL DESCONOCIDO
NULL = NULL DESCONOCIDO
NULL <> NULL DESCONOCIDO

Sí: NULL = NULL no es verdadero. Y tiene toda la lógica del mundo: si no sé la edad de Marta ni la de Iván, no puedo afirmar que sean iguales.

Tablas de verdad de los operadores lógicos (D = desconocido):

A B A AND B A OR B
V V V V
V F F V
V D D V
F F F F
F D F D
D D D D

Dos casillas merecen atención: FALSO AND DESCONOCIDO es FALSO (si una parte ya falla, da igual el resto) y VERDADERO OR DESCONOCIDO es VERDADERO (si una parte ya se cumple, da igual el resto).

La consecuencia que más disgustos causa

Un filtro solo deja pasar las filas para las que la condición es VERDADERO. DESCONOCIDO no pasa. Por eso:

-- MAL: no devuelve NADA, ni siquiera los préstamos abiertos
SELECT * FROM prestamos WHERE fecha_devolucion = NULL;

-- BIEN: el operador correcto para preguntar por la ausencia
SELECT * FROM prestamos WHERE fecha_devolucion IS NULL;

La primera consulta no da error de sintaxis —y eso la hace peligrosa—, simplemente devuelve cero filas siempre. Los operadores correctos son IS NULL e IS NOT NULL. Los practicaremos en 02-03.

Una trampa más sutil, y muy real: WHERE estado <> 'prestado' no devuelve las filas cuyo estado sea NULL, porque NULL <> 'prestado' es DESCONOCIDO. Si quieres incluirlas, hay que pedirlo: WHERE estado <> 'prestado' OR estado IS NULL.

  1. Introducción al álgebra relacional

Codd no se limitó a definir qué es una relación: definió también un álgebra para operar con ellas. La idea es elegante: cada operación toma una o dos relaciones y devuelve otra relación. Al ser cerrado (entra relación, sale relación), se pueden encadenar operaciones indefinidamente, y de ahí nace la posibilidad de consultar.

Aquí solo lo presentamos conceptualmente, sin ejercicios de notación. Lo importante es que veas que cada operación del álgebra tiene su traducción directa en SQL: SQL es la realización práctica del álgebra relacional, y el optimizador que vimos en 01-04 trabaja precisamente reordenando estas operaciones para que cuesten menos.

Selección (σ)

Elige filas que cumplen una condición. El resultado tiene el mismo grado y menor o igual cardinalidad.

"Los ejemplares de la sucursal 2"σ sucursal_id = 2 (ejemplares)

SELECT * FROM ejemplares WHERE sucursal_id = 2;   -- la cláusula WHERE

Proyección (π)

Elige columnas. El resultado tiene menor grado. En el álgebra pura, la proyección elimina duplicados (porque el resultado debe ser un conjunto); en SQL no lo hace salvo que escribas DISTINCT.

"Solo el título y el ISBN de los libros"π titulo, isbn (libros)

SELECT DISTINCT titulo, isbn FROM libros;   -- la lista de columnas del SELECT

Producto cartesiano (×)

Combina cada tupla de una relación con cada tupla de la otra. Si socios tiene 12.000 filas y libros 8.000, el producto tiene 96.000.000. Rara vez se quiere por sí mismo, pero es el fundamento teórico de todas las combinaciones.

SELECT * FROM socios CROSS JOIN libros;   -- CROSS JOIN

Reunión (⋈, join)

Un producto cartesiano seguido de una selección que empareja las tuplas relacionadas. Es la operación que recompone la información repartida en varias tablas.

"Cada préstamo con los datos de su socio"prestamos ⋈ prestamos.socio_id = socios.socio_id socios

SELECT * FROM prestamos JOIN socios ON socios.socio_id = prestamos.socio_id;

Es tan central que le dedicamos la lección entera 02-04.

Unión (∪)

Junta las tuplas de dos relaciones compatibles (mismo número de atributos y dominios compatibles) y elimina duplicados.

"Todos los identificadores de socio que aparecen en préstamos o en reservas"

SELECT socio_id FROM prestamos
UNION
SELECT socio_id FROM reservas;

Diferencia (−)

Las tuplas que están en la primera relación y no en la segunda. Es la operación que responde a las preguntas negativas.

"Socios que han reservado pero nunca han tomado nada prestado"

SELECT socio_id FROM reservas
EXCEPT
SELECT socio_id FROM prestamos;

Un mapa de correspondencias

Operación del álgebra Símbolo Cláusula SQL
Selección σ WHERE
Proyección π lista de columnas del SELECT (+ DISTINCT)
Producto cartesiano × CROSS JOIN
Reunión JOIN ... ON
Unión UNION
Diferencia EXCEPT (MINUS en Oracle)
Intersección INTERSECT
Renombrado ρ AS

Esta tabla es, en la práctica, el índice de las tres lecciones siguientes.

  1. El esquema conceptual de BiblioRed

Con todo el vocabulario en la mano, este es el plano que construiremos en la lección 02-02. Siete relaciones:

erDiagram
    SUCURSALES ||--o{ SOCIOS : "es sucursal de alta de"
    SUCURSALES ||--o{ EJEMPLARES : "custodia"
    AUTORES    ||--o{ LIBROS : "escribe"
    LIBROS     ||--o{ EJEMPLARES : "tiene copias en"
    SOCIOS     ||--o{ PRESTAMOS : "realiza"
    EJEMPLARES ||--o{ PRESTAMOS : "es objeto de"
    SOCIOS     ||--o{ RESERVAS : "solicita"
    LIBROS     ||--o{ RESERVAS : "es objeto de"

    SUCURSALES {
        int sucursal_id PK
        varchar nombre UK
        varchar direccion
        varchar telefono
        date fecha_apertura
    }
    SOCIOS {
        int socio_id PK
        varchar nombre
        varchar apellidos
        varchar email UK
        date fecha_alta
        int sucursal_id FK
        boolean activo
    }
    AUTORES {
        int autor_id PK
        varchar nombre
        varchar apellidos
        varchar nacionalidad
        int anio_nacimiento
    }
    LIBROS {
        int libro_id PK
        varchar isbn UK
        varchar titulo
        int autor_id FK
        varchar editorial
        int anio_publicacion
        varchar idioma
    }
    EJEMPLARES {
        int ejemplar_id PK
        varchar codigo UK
        int libro_id FK
        int sucursal_id FK
        varchar estado
        date fecha_adquisicion
    }
    PRESTAMOS {
        int prestamo_id PK
        int socio_id FK
        int ejemplar_id FK
        date fecha_prestamo
        date fecha_devolucion_prevista
        date fecha_devolucion
        numeric recargo
    }
    RESERVAS {
        int reserva_id PK
        int socio_id FK
        int libro_id FK
        date fecha_reserva
        date fecha_expiracion
        varchar estado
    }

Las decisiones de diseño que ya podemos justificar con lo aprendido:

  • Siete claves primarias subrogadas, una por tabla, todas enteras y autogeneradas. Cumplen la integridad de entidad sin depender de datos del mundo real.
  • libros.isbn y ejemplares.codigo como claves alternativas (UNIQUE): conservamos las restricciones naturales sin convertirlas en clave primaria.
  • La distinción entre libros y ejemplares es la clave del modelo. libros es la obra (el título, el ISBN, el autor); ejemplares es el objeto físico que se presta y que está en una estantería concreta. BiblioRed tiene unos 8.000 libros distintos y 40.000 ejemplares. Prestar un "libro" no significa nada: se presta un ejemplar.
  • prestamos apunta a ejemplares, no a libros, precisamente por lo anterior. reservas, en cambio, apunta a libros: un socio reserva la obra, y ya se le asignará el ejemplar que se libere antes. Esta asimetría no es un descuido, es el modelo del negocio.
  • fecha_devolucion admite NULL y ese NULL significa "préstamo abierto". Es el uso legítimo del valor nulo que vimos en el apartado 9.
  • recargo es NUMERIC, no coma flotante, porque representa dinero. La justificación completa está en la lección siguiente.

Este esquema no es todavía un diseño terminado: un libro puede tener varios autores, y con libros.autor_id solo cabe uno. Es una simplificación consciente para el módulo 2; las técnicas para modelar bien ese caso (diagramas E-R, relaciones N:M, tablas intermedias) llegan en el módulo 4, y la teoría que dice por qué ciertos diseños degeneran, en el módulo 5.

Errores Comunes y Consejos

  • Confundir "relación" con "vínculo entre tablas". Una relación es una tabla. El vínculo es una clave ajena. Es el malentendido número uno del vocabulario relacional.
  • Suponer que las filas tienen un orden. "Los últimos préstamos están al final de la tabla" es falso. Sin ORDER BY no hay orden garantizado, y confiar en el que salga hoy es una avería aplazada.
  • Diseñar tablas sin clave primaria. SQL lo permite, y por eso hay que imponérselo uno mismo. Sin clave primaria puedes acabar con dos filas idénticas que no se pueden actualizar ni borrar por separado.
  • Escribir = NULL en lugar de IS NULL. No da error: devuelve cero filas en silencio. Es el fallo más caro de esta lección.
  • Elegir clave natural por comodidad. El ISBN parece perfecto hasta que aparece el primer folleto municipal sin ISBN o la primera errata que hay que corregir en cascada.
  • Renunciar al UNIQUE porque ya hay clave subrogada. Poner libro_id no autoriza a permitir dos libros con el mismo ISBN. La clave subrogada identifica; la alternativa protege la realidad.
  • Usar NULL como comodín polivalente. Si NULL en estado significa a veces "no lo sé" y a veces "dado de baja", nadie podrá volver a consultar esa columna con confianza. Un NULL, un significado.
  • Consejo: cuando una consulta futura te devuelva menos filas de las esperadas, comprueba primero si hay NULL implicados. La lógica de tres valores está detrás de la mayoría de los resultados "inexplicables".

Ejercicios

Ejercicio 1: Vocabulario formal sobre una relación

Dada esta instancia de la relación ejemplares de BiblioRed:

ejemplar_id codigo libro_id sucursal_id estado fecha_adquisicion
1 EJ-3081 331 2 prestado 2019-03-14
2 EJ-3082 331 1 disponible 2019-03-14
3 EJ-3083 331 3 disponible 2021-06-01
4 EJ-3084 332 1 prestado 2015-11-20

Responde:

  1. ¿Cuál es el grado y cuál la cardinalidad?
  2. Propón un dominio razonable para estado y otro para fecha_adquisicion.
  3. Indica dos superclaves, todas las claves candidatas, la clave primaria elegida y la clave alternativa.
  4. ¿Es {libro_id, sucursal_id} clave candidata? Justifícalo con los datos.
  5. Enumera las claves ajenas de esta relación y hacia dónde apuntan.

Ejercicio 2: Lógica de tres valores

La tabla prestamos contiene estas filas:

prestamo_id socio_id fecha_devolucion recargo
1 14 2026-03-19 0.00
2 15 2026-04-02 1.40
9 14 NULL NULL
12 19 NULL NULL

Di cuántas filas devuelve cada consulta y por qué:

  1. SELECT * FROM prestamos WHERE fecha_devolucion = NULL;
  2. SELECT * FROM prestamos WHERE fecha_devolucion IS NULL;
  3. SELECT * FROM prestamos WHERE recargo > 0;
  4. SELECT * FROM prestamos WHERE recargo > 0 OR fecha_devolucion IS NULL;
  5. SELECT * FROM prestamos WHERE socio_id = 14 AND recargo > 0;
  6. SELECT * FROM prestamos WHERE NOT (recargo > 0);

Ejercicio 3: Traducir preguntas a álgebra relacional

Expresa cada pregunta usando las operaciones del álgebra (σ, π, ⋈, ∪, −) y di qué cláusula SQL le corresponderá. No hace falta sintaxis SQL correcta todavía.

  1. Los códigos de los ejemplares que están en reparación.
  2. Los títulos de todos los libros, sin repetir.
  3. Cada ejemplar acompañado del título de su libro.
  4. Los socios que tienen préstamos o reservas.
  5. Los libros que nunca se han reservado.

Soluciones

Solución 1

  1. Grado 6 (seis atributos: ejemplar_id, codigo, libro_id, sucursal_id, estado, fecha_adquisicion). Cardinalidad 4 (cuatro tuplas). El grado pertenece al esquema; la cardinalidad, a la instancia.
  2. Para estado, un dominio cerrado de etiquetas: {'disponible', 'prestado', 'reparacion', 'baja'}. Para fecha_adquisicion, las fechas válidas del calendario, no posteriores a hoy (una biblioteca no adquiere en el futuro). El primero se implementará con un CHECK, tema de 04-04.
  3. Superclaves: {ejemplar_id}, {codigo}, {ejemplar_id, estado}, {codigo, libro_id, sucursal_id}, el conjunto de todos los atributos… Claves candidatas: {ejemplar_id} y {codigo}, porque ambas identifican y ninguna se puede reducir. Clave primaria: ejemplar_id (subrogada, estable, barata en las claves ajenas de prestamos). Clave alternativa: codigo, declarada UNIQUE, porque la etiqueta física también debe ser única.
  4. No. Con estos datos no se repite ninguna combinación, pero eso es casualidad de la instancia: nada impide que la sucursal 2 tenga dos ejemplares del libro 331 (de hecho es lo normal en una biblioteca). Las claves se determinan por las reglas del negocio, nunca inspeccionando una instancia concreta; una instancia solo puede refutar una clave candidata, jamás confirmarla.
  5. libro_idlibros.libro_id, y sucursal_idsucursales.sucursal_id. Ambas deberían ser NOT NULL: un ejemplar sin libro no tiene sentido y un ejemplar sin sucursal no se puede localizar en la estantería.

Solución 2

# Filas Motivo
1 0 fecha_devolucion = NULL da DESCONOCIDO en las cuatro filas (también donde el valor es NULL). El filtro solo deja pasar VERDADERO. Es la trampa clásica: no falla, calla.
2 2 (préstamos 9 y 12) IS NULL es el operador correcto; devuelve VERDADERO exactamente donde falta el valor.
3 1 (préstamo 2) Para el 1, 0.00 > 0 es FALSO. Para el 9 y el 12, NULL > 0 es DESCONOCIDO, y DESCONOCIDO no pasa el filtro.
4 3 (préstamos 2, 9 y 12) Fila 2: VERDADERO OR FALSO = VERDADERO. Filas 9 y 12: DESCONOCIDO OR VERDADERO = VERDADERO (basta con que una parte se cumpla). Fila 1: FALSO OR FALSO = FALSO.
5 0 Las filas del socio 14 son la 1 (0.00 > 0 es FALSO → V AND F = FALSO) y la 9 (NULL > 0 es DESCONOCIDO → V AND D = DESCONOCIDO, no pasa).
6 1 (préstamo 1) NOT FALSO = VERDADERO (fila 1). NOT VERDADERO = FALSO (fila 2). NOT DESCONOCIDO = DESCONOCIDO (filas 9 y 12): negar algo desconocido sigue siendo desconocido. Este es el punto más contraintuitivo: la 3 devuelve 1 fila y su negación también devuelve 1, no 3.

Solución 3

# Álgebra relacional Cláusula SQL
1 π codigo ( σ estado = 'reparacion' (ejemplares) ) SELECT codigo ... WHERE estado = 'reparacion'
2 π titulo (libros) — la proyección del álgebra ya elimina duplicados SELECT DISTINCT titulo FROM libros
3 ejemplares ⋈ ejemplares.libro_id = libros.libro_id libros JOIN ... ON (lección 02-04)
4 π socio_id (prestamos) ∪ π socio_id (reservas) UNION
5 π libro_id (libros) − π libro_id (reservas) EXCEPT (o un LEFT JOIN ... IS NULL, lección 02-04)

Observa el patrón del punto 5: toda pregunta que empieza por "los que nunca…" es una diferencia. Retenlo, porque en 02-04 y en 02-06 volverá varias veces.

Conclusión

Hemos convertido el vocabulario informal de la primera lección en un modelo con reglas precisas:

  • Una relación es un conjunto de tuplas con los mismos atributos, cada uno con su dominio. Su grado es el número de atributos y su cardinalidad, el de tuplas.
  • Al ser un conjunto, no tiene orden ni duplicados, y eso la separa radicalmente de una hoja de cálculo, donde una fila se identifica por su posición y no por su valor.
  • Las claves forman una jerarquía: superclave → clave candidata (superclave mínima) → clave primaria (la elegida) y claves alternativas (las demás, UNIQUE). Las claves ajenas vinculan unas relaciones con otras.
  • En el debate clave natural frente a subrogada, BiblioRed elige libro_id como primaria y conserva isbn como alternativa: porque no todo tiene ISBN, porque el ISBN se corrige y porque un entero es más barato de replicar.
  • Las tres reglas de integridad: de dominio (los valores pertenecen a su tipo), de entidad (la clave primaria nunca es nula) y referencial (toda clave ajena apunta a algo que existe; su tratamiento práctico es la lección 02-06).
  • NULL significa "no sé", y de ahí la lógica de tres valores: NULL = NULL es DESCONOCIDO, IS NULL es el único operador válido para preguntar por su ausencia, y NOT DESCONOCIDO sigue siendo DESCONOCIDO.
  • El álgebra relacional —selección, proyección, producto cartesiano, reunión, unión, diferencia— es la maquinaria que SQL implementa: cada operación tiene su cláusula, y el optimizador de 01-04 no hace otra cosa que reordenarlas.
  • Y tenemos el plano de BiblioRed: sucursales, socios, autores, libros, ejemplares, prestamos y reservas, con sus claves y sus vínculos.

El plano está dibujado; falta levantarlo. En la lección 02-02, Lenguaje SQL, conocerás el lenguaje con el que se habla con un sistema relacional —por qué es declarativo, qué sublenguajes tiene, cómo se escriben sus tipos de datos— y terminarás ejecutando el script CREATE TABLE completo de las siete tablas dentro de biblioredb. Al acabarla, el diagrama de esta lección habrá dejado de ser un dibujo.

Fundamentos de Bases de Datos

Módulo 1: Introducción a las Bases de Datos

Módulo 2: Bases de Datos Relacionales

Módulo 3: Bases de Datos No Relacionales

Módulo 4: Diseño de Esquemas

Módulo 5: Normalización

Módulo 6: Transacciones, Rendimiento y Seguridad

Módulo 7: Ejercicios Prácticos

Módulo 8: Casos de Estudio

Módulo 9: Recursos Adicionales

© Copyright 2026. Todos los derechos reservados