Ao usar relacionamentos muitos para muitos, a única maneira realista de lidar com isso é com uma tabela de mapeamento.
Digamos que temos uma escola com professores e alunos, um aluno pode ter vários professores e vice-versa.
Então fazemos 3 tabelas
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)
A tabela aluno terá 1000 registros
A tabela professor terá 20 registros
A tabela link_st terá tantos registros quanto links (NÃO 20x1000, mas apenas para os links reais).
Seleção
Você seleciona, por exemplo, alunos por professor 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 você deve sempre usar uma
inner join
aqui. Criando um link
Quando você atribui um professor a um aluno (ou vice-versa, é a mesma coisa) .Você só precisa fazer:
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'
Isso é um pouco um uso indevido de uma junção interna, mas funciona desde que os nomes sejam únicos.
Se você souber os id's, você pode apenas inseri-los diretamente, é claro.
Se os nomes forem não é exclusivo, isso será uma falha e não deve ser usado.
Como evitar links duplicados
É muito importante evitar links duplicados, todos os tipos de coisas ruins acontecerão se você os tiver.
Se você quiser evitar a inserção de links duplicados em sua tabela de links, você pode declarar um
único índice no link (recomendado)
ALTER TABLE link_st
ADD UNIQUE INDEX s_t (student_id, teacher_id);
Ou você pode fazer a verificação na instrução insert (não é realmente recomendado, mas 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)
Isso selecionará apenas 548.785 se esses dados ainda não estão no link_st
table e não retornará nada se esses dados já estiverem em link_st. Portanto, ele se recusará a inserir valores duplicados.
Se você tem uma tabela de escolas, depende se um aluno pode estar matriculado em várias escolas (improvável, mas vamos supor) e os professores podem estar matriculados em várias escolas. Muito possivel.
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
Você pode listar todos os alunos em uma escola assim:
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)