Módulo 3 · 02 | Relaciones entre tablas

MÓDULO 3 · CLASE 2

Relaciones entre tablas

Clase práctica. Tipos de relación (1:N, N:M, 1:1), claves compuestas y dobles relaciones, leídas en el diagrama entidad-relación de tablas_libro.

Idea clave

Una relación describe cuántas filas de una tabla pueden asociarse con cuántas filas de otra. Esa cardinalidad decide dónde va la clave foránea y si hace falta una tabla intermedia.

Base de práctica: tablas_libro

Todos los ejemplos usan la base tablas_libro (30 tablas: alumnos, cursos, profesores, empleados, mascotas, artículos, quinielas…). Si todavía no la cargaste: descargá tablasLibro.sql, creá la base con CREATE DATABASE tablas_libro;, seleccionala con USE tablas_libro; y ejecutá el script en Workbench (File > Open SQL Script).

Descargar tablasLibro.sql (Drive)

1. Los tipos de relación en tablas_libro

TipoEjemplo en tablas_libroCómo se implementa
Uno a muchos (1:N)Un profesor dicta varios cursosFK en el lado «muchos»: cursos.ID_PROFE
Muchos a muchos (N:M)Alumnos y cursosTabla puente alumnos_cursos con dos FK
Dos relaciones con la misma tablaUn partido tiene equipo local y visitanteDos FK hacia equipos: eventos.LOCAL y eventos.VISITANTE
Clave compuestaUn pronóstico apunta a un partido de una jornadaFK de dos columnas: pronosticos(ID_JORNADA, ID_EVENTO)
Uno a uno (1:1)No hay en esta base (ej.: un profesor y su legajo)FK con restricción UNIQUE

Regla práctica

En 1:N la clave foránea siempre va del lado «muchos». Preguntate: «¿un profesor tiene muchos cursos o un curso tiene muchos profesores?». La tabla que se repite (cursos) lleva la FK.

2. El diagrama entidad-relación (DER), paso a paso

Así se ve la parte «academia» de tablas_libro en MySQL Workbench (Database → Reverse Engineer):

profesoresID_PROFE INTNOMBRE VARCHAR(30)APELLIDOS VARCHAR(50)F_NACIMIENTO DATEIndexescursosID_CURSO INTTITULO VARCHAR(50)ID_PROFE INTIndexesalumnos_cursosID_ALUMNO INTID_CURSO INTIndexesalumnosID_ALUMNO INTNOMBRE VARCHAR(30)APELLIDOS VARCHAR(50)F_NACIMIENTO DATEIndexesactuaciones_destacadasID_ALUMNO INTID_CURSO INTACTUACION VARCHAR(120)Indexes1 : N1 : NN : 1
Profesores, cursos, alumnos, la tabla puente alumnos_cursos y actuaciones_destacadas.

Cómo leerlo:

  1. Cada caja es una tabla. El encabezado celeste es el nombre; abajo van las columnas con su tipo de dato.
  2. Mirá los íconos: la llave dorada marca la clave primaria; la llave roja, una columna que es PK y FK a la vez; el rombo rojo, una clave foránea.
  3. Seguí la línea punteada desde la FK (cursos.ID_PROFE) hasta la PK que referencia (profesores.ID_PROFE).
  4. Leé los extremos de la línea con la leyenda: del lado de profesores hay «cero o uno»; del lado de cursos, «cero o muchos».
  5. Armá la frase en los dos sentidos: «un profesor dicta cero o muchos cursos» y «un curso tiene cero o un profesor». Es una relación 1:N opcional: el curso «SQL avanzado» todavía no tiene profesor.
Uno y solo uno (obligatorio)Cero o uno (opcional)Uno o muchosCero o muchosÍconos de columnaClave primaria (PK)Parte de la PK y también FKClave foránea NOT NULLClave foránea opcional (NULL)Columna NOT NULLColumna que admite NULL
Notación «pata de gallo» (crow’s foot) que usa MySQL Workbench.

3. Uno a muchos (1:N): profesores → cursos

profesoresID_PROFE INTNOMBRE VARCHAR(30)IndexescursosID_CURSO INTTITULO VARCHAR(50)ID_PROFE INTIndexes1N
Un profesor → cero o muchos cursos. La FK cursos.ID_PROFE admite NULL.
-- ¿Cuántos cursos dicta cada profesor? (lado "muchos" = cursos) SELECT ID_PROFE, COUNT(*) AS cursos FROM cursos WHERE ID_PROFE IS NOT NULL GROUP BY ID_PROFE; -- 1 → 1 curso · 2 → 1 curso · 3 → 2 cursos -- El profesor 4 (Carlos) no aparece: no dicta ninguno.

4. Muchos a muchos (N:M): alumnos ↔ cursos

Un alumno cursa varios cursos y un curso tiene varios alumnos. Ninguna de las dos tablas puede guardar la FK de la otra, así que existe la tabla puente alumnos_cursos, con clave primaria compuesta:

alumnosID_ALUMNO INTNOMBRE VARCHAR(30)Indexesalumnos_cursosID_ALUMNO INTID_CURSO INTIndexescursosID_CURSO INTTITULO VARCHAR(50)Indexes1 : NN : 1tabla puente: su PK es la combinación (ID_ALUMNO, ID_CURSO)
N:M se descompone en dos relaciones 1:N a través de la tabla puente.
-- Definición (así está en tablasLibro.sql) CREATE TABLE alumnos_cursos ( ID_ALUMNO INT NOT NULL, ID_CURSO INT NOT NULL, PRIMARY KEY (ID_ALUMNO, ID_CURSO) -- evita inscribir dos veces ); -- Probá inscribir de nuevo a Pablo (1) en Programación PHP (1): INSERT INTO alumnos_cursos VALUES (1, 1); -- Error 1062: Duplicate entry '1-1' for key 'alumnos_cursos.PRIMARY'

Dato BI

Una tabla puente es como una tabla de hechos: cada fila es un «evento» (una inscripción) que une dos dimensiones (alumno y curso). Hay 8 inscripciones para 6 alumnos y 5 cursos.

5. Dos relaciones con la misma tabla y claves compuestas

La parte «quinielas» de la base tiene dos casos más avanzados:

jornadasID_JORNADA INTNOMBRE VARCHAR(30)FECHA DATEDISPUTADA VARCHAR(1)IndexeseventosID_JORNADA INTID_EVENTO INTLOCAL INTVISITANTE INTRESULTADO VARCHAR(1)IndexesequiposID_EQUIPO INTEQUIPO VARCHAR(30)IndexesquinielasID_QUINIELA INTID_JORNADA INTNOMBRE VARCHAR(30)ESCRUTADA VARCHAR(1)ACIERTOS INTIndexespronosticosID_QUINIELA INTID_PRO INTID_JORNADA INTID_EVENTO INTPRONOSTICO VARCHAR(1)IndexesLOCALVISITANTEFK compuesta
Jornadas, eventos (partidos), equipos, quinielas y pronósticos.
  • Doble relación: cada partido (eventos) apunta dos veces a equipos: una por el local y otra por el visitante.
  • Clave compuesta: un partido se identifica por (ID_JORNADA, ID_EVENTO). Por eso la FK de pronosticos también tiene dos columnas.
eventosID_JORNADA INTID_EVENTO INTLOCAL INTVISITANTE INTIndexesequiposID_EQUIPO INTEQUIPO VARCHAR(30)IndexesLOCALVISITANTE
Para mostrar los dos nombres hay que unir equipos dos veces, con dos alias distintos.
SELECT e.ID_JORNADA, l.EQUIPO AS local, v.EQUIPO AS visitante, e.RESULTADO FROM eventos AS e INNER JOIN equipos AS l ON l.ID_EQUIPO = e.LOCAL INNER JOIN equipos AS v ON v.ID_EQUIPO = e.VISITANTE WHERE e.ID_JORNADA = 1; -- Celta – Las Palmas (1) · Xerez – Getafe (1) · Nastic – Alcorcón (1)

6. Uno a uno (1:1)

En tablas_libro no hay relaciones 1:1. Si quisieras guardar el legajo de cada profesor aparte, la FK llevaría UNIQUE para que un profesor no tenga dos legajos:

CREATE TABLE legajos_profesores ( ID_LEGAJO INT PRIMARY KEY, ID_PROFE INT NOT NULL UNIQUE, -- UNIQUE convierte la relación en 1:1 TITULO_ACADEMICO VARCHAR(60), FOREIGN KEY (ID_PROFE) REFERENCES profesores (ID_PROFE) );

7. Relación obligatoria u opcional

  • Opcional: la FK admite NULL. cursos.ID_PROFE es NULL en «SQL avanzado» (curso sin profesor).
  • Obligatoria: la FK es NOT NULL. Toda fila de alumnos_cursos tiene alumno y curso.

Por qué importa

Las FK opcionales son la causa de las «filas que desaparecen» con INNER JOIN y de que NOT IN devuelva 0 filas. Lo vas a ver en la próxima clase y en el Módulo 5.

8. Cómo descubrir las relaciones de una base

-- Definición completa de una tabla, incluidas sus FOREIGN KEY SHOW CREATE TABLE cursos; -- Todas las relaciones de la base, desde el diccionario de datos SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'tablas_libro' AND REFERENCED_TABLE_NAME IS NOT NULL ORDER BY TABLE_NAME; -- 14 filas: 13 claves foráneas (la de pronosticos → eventos tiene 2 columnas)

9. Práctica

  • Ejecutá la consulta de information_schema: ¿qué tablas apuntan a equipos y con qué columnas?
  • Intentá inscribir a Pablo en el curso 99: INSERT INTO alumnos_cursos VALUES (1, 99);. ¿Qué error aparece y por qué?
  • Mirando el DER: ¿qué dos tablas relaciona actuaciones_destacadas y qué tipo de relación tiene con cada una?
-- Respuestas -- 1) Solo eventos, dos veces: LOCAL → equipos.ID_EQUIPO y VISITANTE → equipos.ID_EQUIPO -- 2) Error 1452: Cannot add or update a child row: a foreign key constraint fails -- (alumnos_cursos_id_curso_fk): no existe el curso 99 -- 3) alumnos y cursos; 1:N con cada una (un alumno o un curso pueden tener -- cero o muchas actuaciones destacadas)

Bibliografía y recursos online

Los recursos en inglés se pueden leer con el traductor del navegador.

Siguiente clase: INNER, LEFT y RIGHT JOIN.

Scroll al inicio
¿Consultas? Escribinos