Ответ 1
Добавьте еще одну таблицу под названием BookAuthors со столбцами для BookID, AuthorID и NameUsed. Значение NULL для NameUsed означает вывести его из таблицы Author. Это называется таблицей пересечения.
Посмотрим на пример - книги. Книга может иметь 1..n авторов. У автора могут быть 1..m книги. Что представляет собой хороший способ представить всех авторов книги?
У меня возникла идея создать таблицу Books и таблицу авторов. В таблице Авторы есть первичный ключ AuthorID, имя автора. В таблице "Книги" есть основной идентификатор книги и метаданные о книге (название, дата публикации и т.д.). Однако должен быть способ связать книги с авторами и авторами с книгами. И здесь проблема.
Скажем, у нас есть три книги Боба. Однако в одной книге он написал это как Боб, доктор философии. Другой он написал как доктор Боб, а третий написал как доктор Роберт. Я хочу уметь идентифицировать тот факт, что эти авторы на самом деле являются одним и тем же человеком, но приписываются под разными именами. Я также хочу отличить Боба от другого Боба, который писал разные книги.
Теперь давайте добавим еще одну часть в приложение, таблицу Person, которая отслеживает интересных людей. И пусть говорят, что Боб - интересный человек. Я хочу не только сказать, что автор всех трех книг - Боб, но этот интересный Боб - тот же Боб, что и автор Боб.
Итак, какие существуют стратегии для такого потенциально сложного сопоставления, при том, что авторы книги идентифицируются по имени на обложке?
Добавьте еще одну таблицу под названием BookAuthors со столбцами для BookID, AuthorID и NameUsed. Значение NULL для NameUsed означает вывести его из таблицы Author. Это называется таблицей пересечения.
Вам понадобится три таблицы -
Книга будет содержать идентификатор книги, название книги и всю другую информацию, которую вам нужно собрать о книге.
Автор будет содержать идентификатор автора, а также другую информацию, такую как имя, фамилию, которые необходимо собрать для любого автора.
BookAuthors будет состоять из множества ко многим, включая BookID, AuthorID и NameUsed. Это позволило бы книге иметь либо нулевое, либо много авторов, поскольку у автора было либо ноль, либо много книг, а также информация об этом отношении. Например, у вас также может быть столбец в таблице BookAuthor, который описывает отношение автора к книге ( "Отредактировано", "Переднее слово" ).
Я думаю, что ты в значительной степени там. Вам нужна таблица "Книги", таблица "Авторы", а затем таблица "authors_of_books" с основным ключом книги, основным ключом автора и текстовым полем "цитируется как", показывающим, как этот конкретный автор цитировался в этой книге.
Это звучит как отношение "многие ко многим", а не "один ко многим". Я думаю, вы захотите использовать таблицу между этими двумя, которая позволяет вам определять по одному с каждой стороны. Проверьте это...
http://www.tekstenuitleg.net/en/articles/database_design_tutorial/8
Учитывая, что доктор Боб и доктор Роберт и Боб, доктор философии, все те же люди, они будут ссылаться на одну и ту же строку в таблице авторов.
Тем не менее, я думаю, что вам нужна таблица с людьми, на которую ссылаются авторы. Вы также можете связать свою интересную таблицу людей с ней. Таким образом, автор Боб и автор Роберт, а также интересный Боб, ссылаются на Человека Боба. Надеюсь, что это имеет смысл.
Первое, что приходит на ум, - это иметь ссылку, возможно, называемую AuthorOf, чтобы связать книги со своими авторами.
Столбцы будут AuthorID, BookID и, возможно, CreditAs, поэтому вы можете различать доктора Боба и Боба, доктора философии. (А также имена пера, такие как Стивен Кинг и Ричард Бахман).
И вы все еще можете однозначно идентифицировать автора.
Похоже, вы хотите создать серию пользовательских таблиц соединений, которые используются для связывания элементов от одного объекта к другому.
Я бы начал на самом грамотном уровне, и сказал, что ЛЮБОЙ автор должен быть человеком. Я бы упростил этот процесс.
Создайте таблицу лиц с информацией о лицах и PersonId, разместите там информацию.
Создайте таблицу BookAuthors с тремя столбцами BookId, PersonId, TitledName. В этом случае вы можете использовать другое имя, если это необходимо, если нет, вы можете использовать COALESE или что-то подобное, чтобы получить имя по умолчанию, если TitledName имеет значение null.
Просто идея..
То, о чем вы действительно спрашиваете, - это не то, как вы имеете дело с отношениями 1..n, но n..n отношениями (так же эффективно на автора и имеют много книг, а одна книга может иметь много авторов).
Классический способ справиться с этим - через промежуточную таблицу, поэтому
Таблица авторов (authorID, authorDetails) Книжный стол (bookID, подробная информация о книге) Таблица AuthorBook (authorID, bookID)
Если вы действительно беспокоитесь об изменении имен авторов, используйте таблицу сведений о файле 1..n, поэтому добавьте
AuthorDetails (authorID, itemID, authorDetails)
и удалите authorDetails из таблицы автора
Для отношений 1..n(у автора много книг, у автора много псевдонимов):
Если вы хотите, вы можете использовать таблицы-посредники для ссылки на авторов и книги, но с отображением 1..n я не думаю, что это необходимо.
Для отношения n..m(у автора много книг, у книги много авторов):
Вам нужно будет использовать таблицу промежуточных соединений (author_id, alias_id, book_id) вместо внешних ключей в таблице книг. Вы захотите сохранить внешний ключ от псевдонимов до автора (для удобного поиска авторских псевдонимов без необходимости проходить через все их книги).
Можно утверждать, что с точки зрения масштабируемости в будущем это лучший способ начать работу, даже если исходная спецификация говорит, что что-то является отношением 1..n. Вы обнаружите, что спецификация (или вопрос), как это часто дается, неадекватна, поэтому вы захотите спроектировать в общем виде, когда спецификации меняются или уточняются.
возможная реализация в 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 также должен иметь явную максимальную длину для вышеперечисленных varchars):
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", а авторам - только "интересный" флаг. обратите внимание, что ничто не изменяется (структурно), если вы переименуете "авторов" в "людей"