MySQL: Понимание таблиц сопоставления


При создании системы навигации по категориям для бизнес-каталога с отношениями "многие ко многим" я понимаю, что хорошей практикой является создание таблицы сопоставления.

Таблица категорий (идентификатор категории, имя категории)
Бизнес-таблица (идентификатор предприятия, имя предприятия)
Таблица сопоставления категорий (идентификатор бизнеса, идентификатор категории)

Когда я присоединюсь к таблице категорий и бизнес-таблице для создания таблицы сопоставления, это даст мне таблицу, содержащую все возможные отношения бизнеса и категории?

У меня есть 800 категорий и 1000 бизнес-списков. Не даст ли это мне таблицу, содержащую 800 000 возможных отношений? Если да, то как бы я сосредоточился только на существующих отношениях? Должен ли я просмотреть все списки (800 000), отметив их как истинные или ложные?

Я действительно запутался в этом, так что любая помощь была бы очень признательна.

Author: Richard Bell, 2011-06-23

4 answers

При использовании отношений "многие ко многим" единственный реалистичный способ справиться с этим - использовать таблицу сопоставления.

Допустим, у нас есть школа с учителями и учениками, у ученика может быть несколько учителей и наоборот.

Итак, мы составляем 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'

Это немного неправильное использование внутреннего соединения, но оно работает до тех пор, пока имена уникальны.
Если вы знаете идентификаторы, вы можете просто вставить их непосредственно из курс.
Если имена не уникальны, это будет ошибка и не должно использоваться.

Как избежать повторяющихся ссылок
Очень важно избегать повторяющихся ссылок, если они у вас есть, могут произойти всевозможные плохие вещи.
Если вы хотите предотвратить вставку повторяющихся ссылок в таблицу ссылок, вы можете объявить индекс unique для ссылки (рекомендуется)

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

Или вы можете выполнить проверку в инструкции insert (на самом деле не рекомендуется, но это работает).

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)
 23
Author: Johan, 2012-02-04 13:21:56

Когда я присоединюсь к таблице категорий и бизнес-таблице для создания таблицы сопоставления , это даст мне таблицу который содержит все возможные деловые и категориальные отношения?

Да.

Должен ли я просмотреть все списки (800 000), отметив их как истинные или ложные?

Нет, вам нужно использовать предложение ON- для задания условий соединения.

SELECT <columns> FROM categories as c 
INNER JOIN mapping AS m
    ON m.CategoryId = c.CategoryId
INNER JOIN businesses as b
    ON m.BusinessId = b.BusinessId
 2
Author: phant0m, 2011-06-23 11:51:26

Вы помещаете только реальные отношения в таблицу сопоставления. таким образом, в среднем, если бизнес относится к 2 категориям, то в вашем примере в таблице сопоставления будет только 2000 записей, а не 800 000

"Когда я соединяю таблицу категорий и бизнес-таблицу для создания таблицы сопоставления", вы не соединяете эти две таблицы для создания таблицы сопоставления. Вы создаете реальную физическую таблицу.

 1
Author: Gidon Wise, 2011-06-23 11:49:33

Вам следует использовать таблицы сопоставления, когда вы пытаетесь смоделировать отношения "многие ко многим" или "один ко многим".

Например, в приложении адресной книги конкретный контакт может принадлежать к нулю, одной или нескольким категориям. Если вы настроите свою бизнес-логику так, что контакт может принадлежать только к одной категории, вы бы определили свой контакт следующим образом:

Contact
--------------
contactid (PK)
name
categoryid (FK)

Category
--------------
categoryid (PK)
categoryname

Но если вы хотите разрешить контакту иметь более одного адреса электронной почты, используйте таблицу сопоставления:

Contact
--------------
contactid (PK)
name

Category
--------------
categoryid (PK)
categoryname

Contact_Category
--------------
contactid (FK)
categoryid (FK)

Тогда вы можете используйте SQL для получения списка категорий, которым назначен контакт:

выберите.имя категории из категории a, Контакт b, Contact_Category c, где a.categoryid=c.categoryid и b.contactid=c.contactid и b.contactid=12345;

select a.categoryname 
from Category a
inner join Contact_Category c on a.categoryid=c.categoryid
inner join Contact b on b.contactid=c.contactid
where b.contactid=12345;
 1
Author: Matt Healy, 2011-06-23 12:29:24