При использовании отношений «многие ко многим» единственный реалистичный способ справиться с этим - использовать таблицу сопоставления.
Допустим, у нас есть школа с учителями и учениками, у ученика может быть несколько учителей и наоборот.
Итак, мы делаем 3 стола
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)
В таблице учеников будет 1000 записей
Стол учителя будет иметь 20 записей
В таблице link_st будет столько записей, сколько имеется ссылок (НЕ 20x1000, а только для реальных ссылок).
Выбор
Вы выбираете, например, количество учеников на одного преподавателя:
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
Обычно вы всегда должны использовать inner join
здесь.
Создание ссылки
Когда вы назначаете учащегося ученику (или наоборот, это то же самое) .
Вам нужно только сделать:
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'
Это неправильное использование внутреннего соединения, но оно работает, пока имена уникальны.
Если вы знаете идентификаторы, вы, конечно, можете просто вставить их напрямую.
Если имена не уникальны, это будет fail и не должно использоваться.
Как избежать повторяющихся ссылок
Очень важно избегать повторяющихся ссылок, если они у вас будут, произойдут всякие плохие вещи.
Если вы хотите запретить вставку дублирующих ссылок в таблицу ссылок, вы можете объявить индекс unique
для ссылки (рекомендуется)
ALTER TABLE link_st
ADD UNIQUE INDEX s_t (student_id, teacher_id);
Или вы можете выполнить проверку в операторе вставки (не очень рекомендуется, но это работает).
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)
Это выберет только 548, 785 , если , что данные еще не находятся в таблице link_st
, и ничего не вернет, если эти данные уже находятся в link_st. Поэтому он откажется вставлять повторяющиеся значения.
Если у вас есть настольные школы, это зависит от того, может ли ученик быть зачислен в несколько школ (маловероятно, но предположим), и учителя могут быть зачислены в несколько школ. Очень возможно.
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
Вы можете перечислить всех учеников в школе следующим образом:
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)