Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL:Noções básicas sobre tabelas de mapeamento


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)