Lors de l'utilisation de relations plusieurs-à-plusieurs, la seule façon réaliste de gérer cela est d'utiliser une table de mappage.
Disons que nous avons une école avec des enseignants et des élèves, un élève peut avoir plusieurs enseignants et vice versa.
Donc on fait 3 tableaux
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 table des étudiants aura 1000 enregistrements
La table des enseignants aura 20 enregistrements
La table link_st aura autant d'enregistrements qu'il y a de liens (PAS 20x1000, mais seulement pour les liens réels).
Sélection
Vous sélectionnez par ex. élèves par enseignant utilisant :
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
Normalement, vous devez toujours utiliser une inner join
ici.
Faire un lien
Lorsque vous affectez un enseignant à un élève (ou vice versa, c'est la même chose) .Vous n'avez qu'à faire :
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'
C'est un peu une mauvaise utilisation d'une jointure interne, mais cela fonctionne tant que les noms sont uniques.
Si vous connaissez les identifiants, vous pouvez simplement les insérer directement bien sûr.
Si les noms sont pas unique ce sera un échec et ne doit pas être utilisé.
Comment éviter les liens en double
Il est très important d'éviter les liens en double, toutes sortes de mauvaises choses se produiront si vous en avez.
Si vous voulez empêcher l'insertion de liens en double dans votre table de liens, vous pouvez déclarer un unique
index sur le lien (recommandé)
ALTER TABLE link_st
ADD UNIQUE INDEX s_t (student_id, teacher_id);
Ou vous pouvez faire la vérification dans l'instruction d'insertion (pas vraiment recommandé, mais ça marche).
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)
Cela ne sélectionnera que 548, 785 si ces données ne sont pas déjà dans le link_st
table, et ne renverra rien si ces données sont déjà dans link_st. Il refusera donc d'insérer des valeurs en double.
Si vous avez une table d'écoles, cela dépend si un élève peut être inscrit dans plusieurs écoles (peu probable, mais supposons) et si les enseignants peuvent être inscrits dans plusieurs écoles. Très possible.
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
Vous pouvez répertorier tous les élèves d'une école comme suit :
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)