Как вы справляетесь с m..n отношениями в реляционной базе данных? - PullRequest
15 голосов
/ 08 октября 2008

Давайте посмотрим на пример - книги. Книга может иметь 1..n авторов. Автор может иметь 1..m книг. Что такое хороший способ представить всех авторов книги?

У меня возникла идея создать таблицу Books и таблицу Authors. Таблица авторов имеет первичный ключ AuthorID, имя автора. Таблица «Книги» содержит основной идентификатор книги и метаданные о книге (название, дата публикации и т. Д.). Однако должен быть способ связать книги с авторами, а авторов - с книгами. И вот где проблема.

Допустим, у нас есть три книги Боба. Тем не менее, в одной книге он написал это как Боб, доктор философии. Другой он написал как доктор Боб, а третий он написал как доктор Роберт. Я хочу иметь возможность определить тот факт, что эти авторы на самом деле являются одним и тем же лицом, но зачисляются под разными именами. Я также хочу отличить Боба от другого Боба, который написал разные книги.

Теперь давайте добавим еще одну часть к приложению, таблицу Person, которая отслеживает интересных людей. И скажем, Боб интересный человек. Я хочу не только сказать, что автор всех трех книг - Боб, но и этот интересный Боб - тот же Боб, что и автор Боб.

Так, какие стратегии существуют для такого потенциально сложного картографирования, обеспечивая при этом, чтобы авторы книг были идентифицированы по имени на обложке?

Ответы [ 10 ]

29 голосов
/ 08 октября 2008

Добавьте еще одну таблицу с именем BookAuthors со столбцами для BookID, AuthorID и NameUsed. Значение NULL для NameUsed будет означать вместо этого извлечь его из таблицы автора. Это называется таблицей пересечений.

7 голосов
/ 08 октября 2008

Вам понадобятся три стола -

  1. Книга
  2. Автор
  3. BookAuthors

Книга будет содержать идентификатор книги, название книги и всю другую информацию, которую нужно собрать о книге.

Автор будет содержать идентификатор автора, а также другую информацию, такую ​​как Имя, Фамилия, которую вам необходимо собрать о любом данном авторе.

BookAuthors будет объединением «многие ко многим», содержащим BookID, AuthorID и NameUsed. Это позволило бы книге иметь либо ноль, либо много авторов, а у автора - ноль или много книг, а также получить информацию об этих отношениях. Вы также можете, например, иметь столбец в таблице BookAuthor, который описывает отношение автора к книге («Отредактировано», «Предисловие»).

6 голосов
/ 08 октября 2008

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

3 голосов
/ 08 октября 2008

Звучит как отношение многих ко многим, а не как один ко многим. Я думаю, вы захотите использовать таблицу между этими двумя, которая позволяет вам определять 1-ко-многим по обе стороны от этого. Проверьте это ...

http://www.tekstenuitleg.net/en/articles/database_design_tutorial/8

1 голос
/ 08 октября 2008

На самом деле вы спрашиваете не о том, как вы справляетесь с отношениями 1..n, а с отношениями n..n (как, например, об авторе и множестве книг, а в одной книге может быть много авторов).

Классический способ справиться с этим - через промежуточный стол, поэтому

Таблица авторов (authorID, authorDetails) Столик с книгами (bookID, информация о книге) Таблица AuthorBook (authorID, bookID)

Если вы действительно обеспокоены изменением имен авторов, используйте таблицу сведений об авторе 1..n, поэтому добавьте

AuthorDetails (authorID, itemID, authorDetails)

и удалите authorDetails из таблицы автора

1 голос
/ 08 октября 2008

Похоже, что вы хотите создать серию пользовательских таблиц соединения, которые используются для связывания элементов от одного объекта к другому.

Я бы начал с самого детального уровня и сказал бы, что ЛЮБОЙ автор должен быть человеком. Я бы упростил этот процесс.

Создайте таблицу персон с информацией о персонале и PersonId, поместите туда информацию.

Затем создайте таблицу BookAuthors с 3 столбцами BookId, PersonId, TitledName. Таким образом, вы можете использовать другое имя, если это необходимо, если нет, вы можете использовать COALESE или что-то подобное, чтобы получить имя по умолчанию, если TitledName равно нулю.

Просто идея ..

1 голос
/ 08 октября 2008

Первое, что приходит на ум, - это иметь таблицу ссылок, возможно, под названием AuthorOf, чтобы связывать книги с их авторами.

Столбцы будут AuthorID, BookID и, возможно, CreditAs, так что вы можете различить доктора Боба и Боба, доктора наук. (А также псевдонимы, такие как Стивен Кинг и Ричард Бахман).

И вы все еще можете однозначно идентифицировать автора.

1 голос
/ 08 октября 2008

Учитывая, что доктор Боб и доктор Роберт и Боб, доктор философии, являются одним и тем же человеком, они будут ссылаться на одну и ту же строку в таблице авторов.

Тем не менее, я думаю, что вам нужна личная таблица, на которую ссылаются авторы. Вы также можете привязать к нему интересующую вас таблицу. Таким образом, Автор Боб и Автор Роберт, а также Интересный Боб ссылаются на Персона Боб. Надеюсь, что это имеет смысл.

0 голосов
/ 23 июля 2012

возможная реализация в postgresql, просто для удовольствия:

create table books (
  book_id integer primary key,
  title varchar not null
);

create table aliases (
  alias_id integer primary key,
  alias varchar not null
);

create table books_aliases (
  book_id integer references books (book_id),
  alias_id integer references aliases (alias_id),
  primary key (book_id, alias_id)
);

create table authors (
  author_id integer primary key,
  author varchar not null,
  interesting boolean default false
);

create table aliases_authors (
  alias_id integer references aliases (alias_id),
  author_id integer references authors (author_id),
  primary key (alias_id, author_id)
);

create view books_aliases_authors as
  select * from books 
    natural join books_aliases
    natural join aliases
    natural join aliases_authors
    natural join authors;

вместо естественного соединения можно использовать «использование»:

create view books_aliases_authors as
  select *
    from books 
    join books_aliases using (book_id) 
    join aliases using (alias_id) 
    join aliases_authors using (alias_id) 
    join authors using (author_id);

или сделайте сложную вещь для совместимости с mysql (обратите внимание, что для mysql также потребуется явная максимальная длина для приведенных выше вариантов):

create view books_aliases_authors as
  select b.book_id, title, l.alias_id, alias, t.author_id, author, interesting
    from books b
    join books_aliases bl on bl.book_id = b.book_id
    join aliases l on bl.alias_id = l.alias_id
    join aliases_authors lt on lt.alias_id = l.alias_id
    join authors t on t.author_id = lt.author_id;

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

0 голосов
/ 08 октября 2008

Для отношений 1..n (у автора много книг, у автора много псевдонимов):

  1. Поместите внешний ключ author_id в Книги, указывающие на автора.
  2. Создайте новую таблицу author_aliases для хранения информации о псевдонимах.
  3. Поместите внешний ключ alias_id в Books, указывающий на псевдоним (обнуляется, если сведения об авторе не заданы).
  4. Поместить внешний ключ author_id в author_aliases.

Если вы хотите, вы можете использовать промежуточные таблицы для связи авторов и книг, но с отображением 1..n я не думаю, что это необходимо.

Для отношений n..m (у автора много книг, у книги много авторов):

Вы должны использовать промежуточную таблицу соединений (author_id, alias_id, book_id) вместо внешних ключей в таблице книг. Вы захотите сохранить внешний ключ от псевдонимов до автора (для облегчения поиска псевдонимов авторов без необходимости просматривать все их книги).

Вы можете утверждать, что с точки зрения масштабируемости в будущем это также лучший способ начать, даже если в начальной спецификации сказано, что что-то является отношением 1..n. Вы найдете, что спецификации (или вопрос), как они даны, часто неадекватны, поэтому вам нужно будет разработать общий способ, когда спецификации меняются или уточняются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...