Как правильно хранить дружеские ассоциации в базе данных mysql? - PullRequest
2 голосов
/ 18 января 2012

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

Сейчас я думаю о чем-то вроде этого

member_id, friend_id, active, date

member_id будет столбцом пользователя, совершающего вызов, friend_id будет столбцом друга, к которому он пытается привязаться, active будетпереключатель типа 0 = ожидающий, 1 = активный, дата будет просто зарегистрированной датой последнего действия в этой конкретной строке.

Теперь моя путаница заключается в том, что если бы я делал запрос, я бы обычно запрашивал member_id, а затем baseоставшаяся часть запроса связана с другими значениями Friend_id, чтобы отобразить данные в соответствии с нужными людьми.Таким образом, учитывая эту логику, я думаю, что мне нужно иметь 2 строки на запрос.Один, где это member_id, который запрашивает, и friend_id запроса, вставленный в таблицу, затем тот, который противоположен, чтобы я мог запрашивать соответственно каждый раз.Таким образом, в сущности, это как двойное погружение для каждого действия, запрошенного для этой конкретной таблицы, мне нужно сделать два одинаковых действия, чтобы это работало.Что вообще не имеет смысла для меня, поскольку оптимизация идет.Итак, во всем моем вопросе, как правильно обрабатывать данные для таких отношений?Или я на самом деле думаю, что это разумный подход к решению проблемы?

Ответы [ 4 ]

6 голосов
/ 18 января 2012

Если дружба всегда взаимна, то вы можете выбирать между избыточностью данных (то есть в обоих направлениях, имеющих строку) для более простых запросов или учиться жить с немного более сложными запросами. Я бы лично избегал избыточности данных, если бы не было веской причины, иначе - вы не просто тратите место и производительность, но вам нужно быть осторожным при ее применении - простой CHECK не способен ссылаться на другие строки и зависит от вашего СУБД триггер может быть ограничен в том, что он может делать с мутирующей таблицей.

Простой способ обеспечить только одну строку для дружбы - это всегда вставлять нижнее значение в member_id и более высокое значение в friend_id (установите ограничение CHECK (member_id < friend_id) для его принудительного применения). Затем при запросе у вас будет поиск в обоих направлениях - например, поиск всех друзей данного человека (обозначенный person_id) будет выглядеть примерно так:

SELECT *
FROM
    person
WHERE
    id <> :person_id
    AND (
        id IN (
            SELECT friend_id
            FROM friendship
            WHERE member_id = :person_id
        )
        OR
        id IN (
            SELECT member_id
            FROM friendship
            WHERE friend_id = :person_id
        )
    )

Кстати, в этой схеме вы, вероятно, захотите переименовать member_id и friend_id, скажем, friend1_id и friend2_id ...

5 голосов
/ 18 января 2012

Два взгляда на это:

WHERE ((friend_id = x AND member_id = y) OR (friend_id = y AND member_id = x))

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

И наоборот, добавление обеих сторон отношения, так что ваши запросы состоят из

WHERE friend_id = x AND member_id = y

не только упрощает написание запросов, но и облегчает планирование (что означает повышение производительности БД).

Мой голос за последний вариант.

1 голос
/ 18 января 2012

Красиво - нет проблем с вашим столом как есть.

ТАКЖЕ: Я не уверен, если это количество элементов - "один ко многим" или "много ко многим":

http://en.wikipedia.org/wiki/Cardinality_%28data_modeling%29

В: Я должен был сделать запрос. Обычно я запрашиваю member_id, а затем основываю оставшуюся часть запроса на связанных значениях friend_id, чтобы отображать данные соответствующим людям

.

A: Честно говоря, я не вижу проблем с запросом «член к другу» или «друг к члену» (или любых других комбинаций - например, друзей, которые делятся друзьями).Опять же, выглядит хорошо.

0 голосов
/ 18 января 2012

Представьте вспомогательную таблицу, например:

users
user_id, name, ...

friendship
user_id, friend_id, ....

select u.name as user, u2.name as friend from users u
    inner join friendship f on f.user_id = u.user_id
    inner join users u2 on u2.user_id = f.friend_id

Я думаю, это очень похоже на то, что у вас есть, просто поместив запрос в качестве примера.

...