2012-05-17 5 views
6

У меня есть две таблицы в моей базе данных один, чтобы держать пользователей информации (users_table) , а другой следит за друзейулучшения запроса списка друзей: подсчет общих друзей

users_table:

id username  avatar 
1   max  max.jpg 
2   jack  jack.jpg 

friends_table:

id u1_id  u2_id 
1   1   2 
2   1   3 

в каждом профиле пользователя я показать его/ее список друзей

вот мой запрос

select u.id, 
    u.username, 
    u.avatar 
from friends_table f 
join users_table u on f.u1_id = u.id || f.u2_id = u.id 
where u.id <> $profile_id 
    and (f.u1_id = $profile_id || f.u2_id = $profile_id) 

этот запрос выбирает друзьям владельца профили ($ profile_id)

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

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

 foreach ($friends_list_query_resul as $qr){ 
     $friend_id = $qr['id']; 

     $mutual_count = mysql_query 
    ("select count(*) from friends_table where 
    ($u1_id = $friend_id || $u2_id = $friend_id) 
       && 


    ($u1_id IN (SELECT `u1_id`,`u2_id` from friends_table where 
    ($u1_id = $profile_id || $u2_id = $profile_id)) 

|| 

     $u2_id IN (SELECT `u1_id`,`u2_id` from friends_table where 
    ($u1_id = $profile_id || $u2_id = $profile_id)) 


     ") 
     } 
+9

Не бойтесь заглавных букв ... – Lix

+0

Мой совет состоит в том, чтобы извлечь список друзей каждого идентификатора, а с php сделать совпадение между общими друзьями, MSql медленнее, чем другие языки программирования, когда речь идет о манипуляции данными. – jcho360

+0

@ jcho360 Плохой совет. Базы данных имеют тенденцию масштабироваться намного лучше, чем такой подход к памяти в любой момент. Базы данных не «медленнее, чем другие языки программирования, когда речь идет о манипулировании данными», на самом деле они обычно намного быстрее, * если * используется правильно. –

ответ

0

Я решил добавить две строки для каждого отношения друзей к таблице.

id u1_id  u2_id 
1   10   20 
2   20   10 

Это облегчает и ускоряет процесс.

+1

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

0

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

select u.id, 
    u.username, 
    u.avatar 
from friends_table f 
left join users_table u on f.u2_id = u.id 
where f.u1_id = $profile_id 

Объясняю: вошедшего в систему пользователя является тот, чей идентификатор совпадает с f.u1_id. Поэтому мы выбираем только друзей, чьи идентификаторы находятся в f.u2_id.

Тогда, чтобы посчитать общие друзья моих друзей, мы можем использовать запрос, как это:

select count(*) as mutual_count, f.u1_id as mutual_friend_id 
from friends_table f 
where f.u1_id IN (select f.u2_id from friends_table where f.u1_id = {$profile_id}) 

где $ profile_id это идентификатор зарегистрированного пользователя ...

Правильно ли это?

+0

Фактически, о первом запросе, '$ profile_id' также может быть в столбце' f.u2_id' – pomeh

+0

Да , конечно, потому что это МНОГИЕ МНОГИЕ отношения, но когда оно находится в 'f.u2_id', это означает, что Я ЕСМЬ ДРУГА кого-то, чей идентификатор находится в' f.u1_id' - это отношение не является вопросом для нас (или не должно быть), когда собираешь только моих друзей ... Не пользователи, которых я являюсь другом ... – shadyyx

+0

это не совсем так! Я думаю, это зависит от варианта использования. @max, что вы думаете? – pomeh

1

Вашего первый запрос также может быть записан в виде:

select distinct u.id, 
     u.username, 
     u.avatar 
    from users_table u where u.id in 
     (select case when u1_id=$profile_id then u2_id else u1_id end 
     from friends_table f where case when u1_id=$profile_id 
     then u1_id else u2_id end =$profile_id); 

Взаимные друзья запрос можно записать в виде одного запроса в аналогичном образе:

select u.id, (select count(f.id) from friends f where 
    case when f.u1_id=u.id then u2_id else u1_id end in 
     (select distinct case when u1_id=$profile_id then u2_id else u1_id end 
     from friends where case when u1_id=$profile_id then u1_id else u2_id 
     end =$profile_id) 
    and u1_id=u.id or u2_id=u.id and 
    (u1_id <> $profile_id and u2_id <> $profile_id)) 
as mutual_frnds from user u where u.id <> $profile_id; 

но вы можете тест производительности либо из них перед использованием.

+0

Я надеялся сделать это, не используя подпросы. я собираюсь проверить производительность и посмотреть. thanx для replay – max

1

Все, что вам нужно, это один запрос:

select id, username, avatar, -- ... 
(
    select count(*) 
    from friends_table f1 
    inner join friends_table f2 on f1.u2_id = f2.u1_id and f2.u2_id = f1.u1_id 
    where f1.u1_id = users_table.id 
) 
as mutual_friend_count 
from users_table 

Значение подзапроса является:

Дайте мне счет из «друг друга» отношения пользователь участвует в, так что Цель первого отношения друга является источником второго отношения друга, а целью второго отношения друга является источник первого.

+1

thanx, но я думаю, что для этого мне нужно изменить способ хранения данных в базе данных. прямо сейчас каждый пользователь может либо находиться в u1_id, либо u2_id для каждого отношения, поэтому я должен проверить оба, и я не могу просто сказать select u1_id. – max

+0

Если вам нужно учитывать взаимные отношения между людьми, это означает, что отношения дружбы, которые вы храните, не коммутируют, т. Е. Если u1 является другом u2, это не означает, что u2 является другом u1. Если они не коммутируют, пара (u1, u2) не совпадает с парой (u2, u1). Как я вижу, одна колонка в вашей таблице friends_table должна быть «источником» отношения, а другая должна быть «целевой». Что мне не хватает? –

+0

вещь - дружба .. подходит. если я попрошу вас стать моим другом, и вы согласитесь, вы мой друг, а я ваш. по крайней мере, так оно работает в моем коде – max

Смежные вопросы