Список друзей: дизайн таблицы реляционной базы данных - PullRequest
3 голосов
/ 17 июня 2010

Итак, современная концепция списка друзей:
Допустим, у нас есть таблица с именем Person. Теперь у этого персонажа должно быть много друзей (из которых каждый приятель также входит в класс человека). Самый очевидный способ построить отношения - это таблица соединений. т.е.

buddyID   person1_id   person2_id
0         1            2
1         3            6

Но, когда пользователь хочет увидеть свой список друзей, программа должна будет проверить столбцы person1_id и person2_id, чтобы найти всех своих друзей.

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

buddyID   person1_id   person2_id
0         1            2
1         2            1

Так что нужно искать только один столбец.

Заранее спасибо.

Ответы [ 2 ]

5 голосов
/ 17 июня 2010

Здесь есть несколько возможных сценариев.

Во-первых, вам нужно определить, могут ли отношения с приятелями быть односторонними.Может ли человек А быть приятелем для человека Б, если Б не дружит с А?Я бы предположил, что нет, но это стоит того, чтобы быть явным.

Commonsense предложил бы вам запрашивать больше, чем обновлять отношения.Поэтому оптимизируйте свои данные для этого.При создании отношений друзей создайте две записи: от А до В и от В до А. Это сделает запрос тривиальным.Так что да, иди с двумя записями, которые ты уже рассмотрел.

2 голосов
/ 17 июня 2010

Это отношение многие ко многим, требуется таблица отношений.

create table Person (
   person_id int not null primary key,
   username varchar(100) not null,
   ... other_cols ...
)


create table Buddy (
   person_id1 int not null,
   person_id2 int not null,
   primary key (person_id1, person_id2),
   foreign key (person_id1) reference Person (person_id),
   foreign key (person_id2) reference Person (person_id)
)

Таким образом, таблица Person будет содержать по 1 строке для каждого Person. Он будет содержать любые данные о приятелях, так как это сделает его денормализованным. Вместо этого таблица друзей будет содержать отношения между людьми.

Допустим, у вас есть что-то вроде этого в таблице Person:

person_id    username
1            George
2            Henry
3            Jody
4            Cara

Генри и Кара - приятели, как Джордж и Кара, так:

person_id1   person_id2
2            4
1            4

Если вам нужно, чтобы отношения не были неявно взаимными, вам нужно добавить дополнительные строки, чтобы сделать это явным. Итак, теперь давайте скажем, что Генри считает Кара приятелем, и Кара также думает о Генри как приятеле, в то время как Джордж рассматривает Кара как друга, но Кара не отвечает взаимностью с Джорджем:

person_id1   person_id2
2            4
4            2
1            4

Отсутствующий 4 1 указывает на то, что Кара не считает Джорджа своим другом. Это делает вещи очень чистыми и позволяет избежать аномалий данных. Вы можете настроить отношения, не копаясь с данными человека. Также вы можете определить правило удаления каскадов для внешних ключей, чтобы удаление Person автоматически удаляло все связанные с вами отношения. И наоборот, вы можете захотеть предотвратить это, вместо этого в этом случае вы можете указать ограничение (по умолчанию) для внешних ключей, что предотвратит удаление Person с еще определенными отношениями.

Запросы тоже просты:

Сколько друзей имеет Cara (допустим, что отношения для списков друзей неявны):

select count(*) from Person 
                join Buddy on person_id = person_id1 or person_id = person_id2
 where name = 'Cara'

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

person_id   considers_as_buddy_id
2           4
4           2
1           4
4           3

select count(*) from Person P
                join Buddy B on P.person_id = B.person_id
 where name = 'Cara'

Возвращает количество людей, которых Кара считает друзьями. В данном случае 2. Хотя Джоди не думает о Каре как о Бадди - поэтому, чтобы выяснить взаимоотношения, вы должны сделать это:

select count(*) from Person P
                join Buddy B on P.person_id = B.person_id and 
                                B.considers_as_buddy_id = P.person_id
 where name = 'Cara'
...