sql >> Base de Datos >  >> RDS >> Mysql

MySQL:comprensión de las tablas de mapeo

Cuando se usan relaciones de muchos a muchos, la única forma realista de manejar esto es con una tabla de mapeo.

Digamos que tenemos una escuela con profesores y alumnos, un alumno puede tener varios profesores y viceversa.

Entonces hacemos 3 mesas

student
  id unsigned integer auto_increment primary key
  name varchar

teacher
  id unsigned integer auto_increment primary key
  name varchar

link_st
  student_id integer not null
  teacher_id integer not null
  primary key (student_id, teacher_id)

La tabla de estudiantes tendrá 1000 registros
La tabla de profesores tendrá 20 registros
La tabla link_st tendrá tantos registros como enlaces (NO 20x1000, pero solo para los enlaces reales).

Selección
Usted selecciona, p. estudiantes por maestro usando:

SELECT s.name, t.name 
FROM student
INNER JOIN link_st l ON (l.student_id = s.id)   <--- first link student to the link-table
INNER JOIN teacher t ON (l.teacher_id = t.id)   <--- then link teacher to the link table.
ORDER BY t.id, s.id

Normalmente deberías usar siempre una inner join aquí.

Crear un vínculo
Cuando asignas un profesor a un alumno (o viceversa, es lo mismo) .Solo necesitas hacer:

INSERT INTO link_st (student_id, teacher_id) 
   SELECT s.id, t.id 
   FROM student s 
   INNER JOIN teacher t ON (t.name = 'Jones')
   WHERE s.name = 'kiddo'

Esto es un poco mal uso de una unión interna, pero funciona siempre que los nombres sean únicos.
Si conoce las identificaciones, puede insertarlas directamente, por supuesto.
Si los nombres son no es único esto será un fallo y no debe usarse.

Cómo evitar enlaces duplicados
Es muy importante evitar enlaces duplicados, todo tipo de cosas malas sucederán si los tiene.
Si desea evitar la inserción de enlaces duplicados en su tabla de enlaces, puede declarar un unique índice en el enlace (recomendado)

ALTER TABLE link_st
  ADD UNIQUE INDEX s_t (student_id, teacher_id); 

O puede hacer la verificación en la declaración de inserción (realmente no se recomienda, pero funciona).

INSERT INTO link_st (student_id, teacher_id) 
  SELECT s.id, t.id
  FROM student s
  INNER JOIN teacher t ON (t.id = 548)
  LEFT JOIN link_st l ON (l.student_id = s.id AND l.teacher_id = t.id)
  WHERE (s.id = 785) AND (l.id IS NULL)

Esto solo seleccionará 548, 785 si esos datos no están ya en el link_st table, y no devolverá nada si esos datos ya están en link_st. Por lo tanto, se negará a insertar valores duplicados.

Si tiene escuelas de mesa, depende de si un estudiante puede inscribirse en varias escuelas (poco probable, pero supongamos) y si los maestros pueden inscribirse en varias escuelas. Muy posible.

table school
  id unsigned integer auto_increment primary key
  name varchar

table school_members
  id id unsigned integer auto_increment primary key
  school_id integer not null
  member_id integer not null
  is_student boolean not null

Puede enumerar a todos los estudiantes en una escuela así:

SELECT s.name
FROM school i
INNER JOIN school_members m ON (i.id = m.school_id)
INNER JOIN student s ON (s.id = m.member_id AND m.is_student = true)