Многие-ко-многим на одном столе

Забавно, что я еще никогда не сталкивался с этим!

Мне никогда не приходило в голову, что на одной таблице могут быть отношения "многие-многие", пока я не начал работать в системе, где пользователи могут "дружить" друг с другом (социальные сети).

Стандартная таблица поиска, по крайней мере, так, как я использую ее, здесь не подходит. Давайте упростим:

Таблица пользователя имеет столбец "id" и "name".

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

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

т.д.: uid1 = 1 uid2 = 2

То же, что и:

uid1 = 2 uid2 = 1

И поэтому может вернуть 2 записи или 0 записей, если запрос выполнен неправильно.

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

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

Прежде чем вы спросите, я еще ничего не пробовал, потому что я уже вижу, что мой любимый способ связать вещи (таблицы поиска) недостаточен для моих нужд здесь, и мне нужна помощь - я ничего не могу найти на SO или Google: (

Спасибо заранее.

Ответ 1

означает, что уникальные ключи становятся ошибочными.

uid1 = 1 uid2 = 2

То же, что и:

uid1 = 2 uid2 = 1

Нет, это не так.

На Facebook, например, у меня есть несколько клиентов, которые отправили запросы стать "друзьями", которых я никогда не принимал... Поскольку они просто знакомые.

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

В принципе, в кортеже (uid1, uid2) имеется гораздо больше информации, чем просто идентификаторы.

Убедитесь, что вам никогда не нужно иметь дело с такими ситуациями, прежде чем принимать решение о добавлении, например. a uid1 < uid2 для вашей таблицы.

Ответ 2

Если отношения, которые вы описываете, являются симметричными, как в "Боб - друг Джо" означает "Джо тоже друг Боба", тогда вы можете убедиться в своем коде, что меньший из двух идентификаторов пользователя переходит в первый столбец, а второй - во второй столбец. Это ограничение в значительной степени гарантирует, что записи в вашей таблице поиска будут уникальными. Это также означает, что когда вы выполняете поиск, вам обычно приходится искать оба столбца.

Например, если вы пытались найти всех друзей Боба, вам придется запрашивать записи, содержащие идентификатор Bob в любом столбце. Это приводит к еще большему количеству кода и, возможно, к снижению производительности.

Если отношения могут быть асимметричными, как в "Боб - друг Джо", это не обязательно означает, что "Джо тоже друг Боба", тогда вам нужно 2 записи для каждой пары пользователей: Bob - Joe and Joe - Боб. Это означает, что ваша таблица поиска будет содержать в два раза больше записей, а также то, что ваш сайт очень дружелюбен: D Конечно, вы все равно можете применить эту систему, даже если ваши отношения симметричны.

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

Ответ 3

Это не так уж редко.

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

Как вы указали userId1 и userId2. Атрибуты, если необходимо, могут быть добавлены к отношениям (например, к классификации дружбы).

Когда пользователь 1 подружится с пользователем 2, обычно есть две вставки, (1,2) и (2,1).

То же, что и с недружественным, должно быть два удаления.

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

Это очень зависит от того, как приложение написано поверх базы данных.

Ответ 4

Я согласен с тем, что говорили другие, неплохо было иметь 2 вставки для отношений (1: 2 и 2: 1). Это фактически помогает расширить некоторые функции, которые обычно встречаются в современных социальных сетях. Некоторые примеры практического использования, о которых я могу думать, - это описание отношений или других атрибутов. В то время как люди остаются друзьями, они поддерживают разные настройки друг к другу. В отношениях 1: 2 Боб следит за обновлениями Джо и имеет его в списке лучших друзей (добавьте столбец bff), а в 2: 1 Джо не имеет Боба в списке bff и не хочет следить за его сообщениями (следующая колонка).