2015-08-28 3 views
0

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

поэтому я хранил userId из 2 друзей соответственно.

Гола

Пользователь хочет, чтобы загрузить его/ее список друзей.

t_friends Вариант 1:

enter image description here

Запрос

SELECT * FROM t_friend WHRE user_id = 10 

10 является текущим userId пользователя, который ищет свой список друзей, и он имеет 1 друга userId(20)

Этот способ userId (10) находит своего друга (20) НО что, если userId(20) искали друзей? Запрос связан с userId.

Это подводит меня к другой конструкции, который содержит избыточные данные:

t_friends вариант 2:

enter image description here

userId (10) нагрузки в настоящее время:

SELECT * FROM t_friend WHRE user_id=10 

похож на этот запрос для userId(20) будет:

SELECT * FROM t_friend WHRE user_id=20 

А как насчет избыточности? Это приводит меня тогда к этому запросу, используя вариант дизайна таблицы 1:

SELECT * FROM t_friend WHERE user_id=10 OR friend_id=10 

У меня есть ощущение, что есть более разумный способ решить это. Есть ли у вас опыт в этой структуре?

Благодаря

+2

насчет избыточности? То, что вы сделали, прекрасно, и нет более разумного способа, независимо от того, что кто-нибудь напишет об этом. Вы запрашиваете друзей пользователя. Ваши данные нормализованы, и все просто отлично. Если вы можете добиться чего-либо, пытаясь «оптимизировать», это разрушает все это, создавая ненужные сложные запросы и делая систему, которую трудно поддерживать. Независимо от того, кто или какой опыт у них есть с SQL, когда люди видят созданную вами таблицу - все имеет смысл на первый взгляд. TL; DR: ничего не меняйте. – Mjh

+0

Спасибо @Mjh. но таким образом мы имеем вдвое больше данных. Вместо того, чтобы иметь, например, 10 ГБ, у вас будет 20 ГБ для сканирования и т. Д. –

+2

@bub Окончательный запрос, который вы использовали, совершенно прекрасен, и мне кажется, что проблема слишком задумана. Одна строка для каждой связи использует запрос OR. Вы можете использовать IF, чтобы избежать этого в php: 'SELECT IF (user_id = 10, friend_id, user_id) AS target_id FROM t_friend WHERE user_id = 10 ИЛИ friend_id = 10' –

ответ

2

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

SELECT * FROM t_friend WHERE user_id=10 OR friend_id=10 
+0

Спасибо. Почему минимальное и максимальное разделение? –

+0

Форма, которую вы не хотите выполнять дополнительный поиск при вставке значений –

-1

Вы можете захотеть использовать следующий запрос, который проверить, если ваш пользователь уже не друг другой первый:

INSERT INTO t_friend (userId, friendId) 
SELECT 10, 20 
WHERE NOT EXISTS ( SELECT userId 
        FROM t_friend 
        WHERE userId = 20 
        AND friendId = 10) 

Благодаря этому (французский) тему о проверке избыточности here.

+0

Спасибо. Но это не помогает, так как вы не знаете идентификатор друзей. Но ваш запрос предполагает узнать идентификатор пользователя с 20. –

+0

Итак, вы должны добавить еще одну точность о том, как вы вставляете свои значения, я думаю, вы знаете идентификатор обоих пользователей, прежде чем вставлять строку, правильно? –

+0

Да, я знаю оба идентификатора, когда я вставляю. Но что вы подразумеваете под другой точностью? –

2

Добавить поле friendship_key:

ALTER TABLE ADD t_friend friendship_key десятичной (22,11);

СОЗДАТЬ УНИКАЛЬНЫЙ ИНДЕКС friendship_key_unique ON t_friend (friendship_key);

И PHP часть:

$friends = [$userId, $friendId]; 
$key = min($friends).'.'.max($friends); 

$q = "SELECT * FROM t_friend WHERE friendship_key = ".$key; 

вставки:

$friends = [$userId, $friendId]; 
$key = min($friends).'.'.max($friends); 

$q = "INSERT INTO t_friend (friendship_key, userId, friendId) VALUES (".implode(',', [$key, $userId, $friendId]).")"; 

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

Чтобы сохранить это просто просто создать функции:

function insertFriendship($user1, $user2) { 
    $key = min([$user1, $user2]).'.'.max([$user1, $user2]); 
    $q = "INSERT INTO t_friend (friendship_key, userId, friendId) VALUES (".implode(',', [$key, $user1, $user2]).")"; 
    mysql_query($q); 
} 

function getFriendsOf($user) { 
    $q = "SELECT * FROM t_friends WHERE ".$user." IN (userId, friendId)"; 
    return mysql_query($q); 
} 

function areFriends($user1, $user2) { 
    $key = min([$user1, $user2]).'.'.max([$user1, $user2]); 
    $q = "SELECT 1 FROM t_friends WHERE friendship_key = ".$key." LIMIT 1"; 
    $q = mysql_query($q); 
    return (mysql_num_rows($q)>0); 
} 
+1

Спасибо за ваши усилия :) Я должен реализовать ваше решение, и как только оно будет работать, я соглашусь. спасибо –