Ассоциация между двумя записями в таблице SQL - PullRequest
5 голосов
/ 14 октября 2010

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

Полагаю, в этом случае нужна вторая таблица для хранения ассоциаций людей. Эта таблица будет содержать два поля (person1, person2), и каждая запись соответствует взаимно-однозначному отношению двух людей.

Это правильно или есть более умный способ сделать это? Этот метод делает таблицу ассоциаций масштабируемой как n_users ^ 2.

Ответы [ 3 ]

8 голосов
/ 14 октября 2010

1. Для отношений один-к-одному:

например. таблица UserInfo (для персональной информации пользователей) и таблица UserCredential (для регистрационной информации пользователей). Это разделение таблицы для уменьшения размера одной записи.

Укажите один и тот же первичный ключ для каждой таблицы и создайте внешний ключ от одной (вторичная таблица) к другой (первичная таблица):

UserInfo(#UserID);
UserCredential(#UserID)
    FOREIGN KEY (UserID) REFERENCES UserInfo(UserID);

Столбец с префиксом "#" является первичным ключом таблицы.

2. Для отношений «многие к одному»:

например. Стол сотрудника и стол отдела. Каждый сотрудник принадлежит только одному отделу, но в отделе может быть от нуля до нескольких сотрудников.

Добавьте столбец первичного ключа таблицы Department в таблицу Employee и создайте FK из Emp в Dep:

Department(#DepartmentID);
Employee(#EmployeeID, DepartmentID)
    FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID);

Если вам часто требуется запросить столбец Employee.DepartmentID, вы можете создать для него индекс:

CREATE INDEX IX_Employee_DepartmentID ON Employee(DepartmentID);

3. Для отношений «многие ко многим»:

например. Пользователь стола и сам. Пользователь может быть другом другого пользователя, и дружба является двусторонней (A - друг B, поэтому B - также друг A). И пользователь может следовать за другим пользователем, но следующее является односторонним (A следует за B, но B может не следовать за A одновременно). В теории графов дружба - это неориентированный граф, а ниже - ориентированный граф.

Для представления отношения «многие ко многим» требуется отдельная таблица:

User(#UserID);
Friendship(#LeftUserID, #RightUserID)
    FOREIGN KEY (LeftUserID) REFERENCES User(UserID)
    FOREIGN KEY (RightUserID) REFERENCES User(UserID)
    CHECK (LeftUserID < RightUserID);
Following(#LeftUserID, #RightUserID)
    FOREIGN KEY (LeftUserID) REFERENCES User(UserID)
    FOREIGN KEY (RightUserID) REFERENCES User(UserID)
    CHECK (LeftUserID <> RightUserID);

Обе таблицы Friendship и Follow используют комбинированный первичный ключ (который имеет два или более столбцов).

Проверка-ограничение в таблице Friendship запрещает такие записи, как:

  • (A, A): нельзя быть другом самого себя.
  • (B, A): для дружбы между A и B достаточно записи (A, B). Это случай принципа DRY .

Проверочное ограничение в следующей таблице запрещает только такие записи, как (A, A). (A, B) означает, что A следует за B, а (B, A) означает, что B следует за A, эти две записи имеют разное значение, поэтому обе они необходимы.

Вы можете создать дополнительный индекс для оптимизации запросов со вторым столбцом (предположим, что PK является кластеризованным индексом):

CREATE UNIQUE INDEX IX_Friendship_Right_Left
    ON Friendship(RightUserID, LeftUserID);
CREATE UNIQUE INDEX IX_Following_Right_Left
    ON Following(RightUserID, LeftUserID);
5 голосов
/ 14 октября 2010

Да, это правильно, если вы хотите смоделировать отношение многие ко многим. То есть все люди могут иметь много друзей.

Если у вас есть отношение «один ко многим», так как у всех людей есть один босс (или нет босса), вам не нужна дополнительная таблица, тогда вам нужен только столбец BossId в таблице людей.

0 голосов
/ 14 октября 2010

Вы также можете установить тип выпуска. В этом случае вы бы идеально использовали 2 таблицы, RelationshipTypes и Relationships. Уникальный ключ может быть во всех 3 полях Отношения.

Relationships
  PersonId
  RelatedPersonId
  RelationshipTypeId

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