SQL Tema 6
Tablas relacionadas
En el mundo real, la información no está en una sola tabla gigante. Está repartida en varias tablas que se «conectan» entre sí. Esto evita repetir datos y mantiene la base de datos organizada.
El concepto de clave foránea (Foreign Key)#
Para conectar dos tablas usamos una clave foránea (Foreign Key, FK): una columna de una tabla que guarda el ID (la clave primaria, PK) de una fila de otra tabla.
| Tabla | Papel | Clave primaria (PK) | Clave foránea (FK) |
|---|---|---|---|
alumnos | Tabla padre: existe por sí sola | id_alumno | — |
tutores | Tabla hija: cada tutor apunta a un alumno | id_tutor | id_alumno, que apunta a alumnos |
Importante
SQLite tiene desactivadas por defecto las claves foráneas. En cada sesión (cada vez que abras DBeaver u otro programa) debes ejecutar este comando para activarlas:
PRAGMA foreign_keys = ON;-- En MySQL no hace falta: las claves foráneas están siempre activadasCreación de tablas con relaciones#
Al crear la tabla hija, debemos avisar a SQL de que una de sus columnas está conectada a otra tabla. La tabla alumnos ya la tenemos del tema de creación de tablas; ahora creamos la de tutores:
CREATE TABLE tutores (
id_tutor INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
pago TEXT NOT NULL CHECK (pago IN ('Efectivo', 'Bizum')),
id_alumno INTEGER,
FOREIGN KEY (id_alumno) REFERENCES alumnos(id_alumno)
);CREATE TABLE tutores (
id_tutor INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100) NOT NULL,
pago VARCHAR(10) NOT NULL CHECK (pago IN ('Efectivo', 'Bizum')),
id_alumno INT,
FOREIGN KEY (id_alumno) REFERENCES alumnos(id_alumno)
);La última línea se lee así: «la columna id_alumno de esta tabla tiene que coincidir con algún id_alumno de la tabla alumnos».
Inserción de datos con relaciones#
¡Importante! No puedes asignar un tutor a un alumno que no existe. Por eso, primero se insertan los alumnos (ya los tenemos) y después los tutores, indicando el id_alumno de cada uno:
INSERT INTO tutores (nombre, pago, id_alumno) VALUES
('Juana', 'Efectivo', 1),
('Paco', 'Bizum', 2),
('Pepe', 'Bizum', 3),
('Marta', 'Efectivo', 4);Si intentas INSERT INTO tutores (nombre, pago, id_alumno) VALUES ('Luis', 'Bizum', 99);, SQLite dará un error, porque no hay ningún alumno con id_alumno 99. Esa es justo la protección que da la clave foránea.
Consultas con relaciones (INNER JOIN)#
Cuando queremos ver a la vez el nombre del alumno y el de su tutor, usamos el superpoder del JOIN. Es como decirle a SQL: «junta estas dos tablas usando el ID que tienen en común».
SELECT alumnos.nombre AS alumno, tutores.nombre AS tutor, tutores.pago
FROM alumnos INNER JOIN tutores ON tutores.id_alumno = alumnos.id_alumno;El resultado:
| alumno | tutor | pago |
|---|---|---|
| Antonio | Juana | Efectivo |
| María | Paco | Bizum |
| Juan | Pepe | Bizum |
| Elena | Marta | Efectivo |
¿Qué está pasando aquí?
| Parte | Qué hace |
|---|---|
SELECT | Eliges qué columnas quieres ver de cada tabla, con tabla.columna |
AS | Le pone otro nombre a la columna en el resultado (las dos se llamaban nombre) |
FROM | Eliges la tabla principal |
INNER JOIN | Eliges la tabla que quieres «pegar» |
ON | Explicas cuál es el conector: dónde el ID de una coincide con el ID de la otra |
Errores frecuentes#
| Mensaje o síntoma | Qué significa | Cómo se arregla |
|---|---|---|
FOREIGN KEY constraint failed | El id_alumno del tutor no existe en alumnos, o intentas borrar un alumno que todavía tiene tutores | Inserta primero el alumno; para borrarlo, borra antes sus tutores |
ambiguous column name: nombre | Las dos tablas tienen una columna nombre y SQL no sabe cuál quieres | Indica la tabla: alumnos.nombre o tutores.nombre |
| La clave foránea no protege nada: se pueden meter IDs que no existen | En SQLite no se ha ejecutado PRAGMA foreign_keys = ON; en esta sesión | Ejecútalo cada vez que abras DBeaver |
El JOIN devuelve muchísimas filas repetidas | Falta el ON, o el ON compara columnas que no son | Une por la clave: ON tutores.id_alumno = alumnos.id_alumno |