簡體   English   中英

推薦朋友的MySQL查詢幫助

[英]Mysql Query Help for Recommended friends

我必須從sql表中找到朋友的朋友(而不是我的朋友),但問題是,排除了已經是我的朋友或某些被阻止的朋友的用戶。

這是查詢

SELECT 
  IF(Friends.User_Id1 IN (1111,2222),
       Friends.User_Id2,
       Friends.User_Id1) AS 'Friend_Id', 
  CONCAT(User_FirstName," ",User_LastName) AS User_FirstName,
  User_ProfilePic 
FROM Users
JOIN Friends ON
  IF(Friends.User_Id1 IN (1111,2222),
       Friends.User_Id2,
       Friends.User_Id1) = Users.User_Id
WHERE 
 (Friends.User_Id2 IN (1111,2222) OR Friends.User_Id1 IN (1111,2222)) AND 
 (Friends.User_Id2 != MY_ID AND Friends.User_Id1 != MY_ID AND Friends.Status = 1)
LIMIT 10;

在上述情況下,1111和2222是我的朋友,我試圖讓他們的所有朋友都很好,但我想要的是:

  1. 用戶既是我的朋友,又是1111和2222的朋友,並顯示在列表中。 我不希望他們在這里,因為他們已經在另一個朋友列表中。
  2. 我已阻止的用戶,即MY_ID和friends_friend_id = 3的Friends.Status,我也有一個用戶,用戶ID 3333是2222的朋友,我已經阻止了他,但他在列表中。

如果通過IN(1111,2222)的搜索將來也會導致某些問題,請指導我,因為朋友數肯定會增加。 在上述查詢之前,我使用group_concat用逗號分隔了我的朋友列表。 所有這些都在存儲過程中。

我希望我能清楚地解釋這個問題。

第一件事是您不應該執行我的第一個答案 相反,您應該更改或約束自己的schema 請參閱下面的建議。

據我了解您的架構,它是:

create table Friends (
   user_Id1 int,
   user_Id2 int,
   status int);

只要有朋友關系,id之一就在位置1,而1則在位置2。

現在,假設我的ID為1212,我的朋友ID列表為:

 select user_Id1 as my_friends_userId
   from Friends f
   where f.user_Id2 = '1212'
      and status = 1
 union
 select user_Id2 as my_friends_userId
   from Friends f
   where f.user_Id1 = '1212'
     and status = 1;

我的朋友的朋友ID的列表是:

select f1.user_id1 as friends_of_friends
  from Friends f1
  where f1.user_Id2 in (select user_Id1 as my_friends_userId
      from Friends f
      where f.user_Id2 = '1212'
        and status = 1
      union
      select user_Id2 as my_friends_userId
      from Friends f
      where f.user_Id1 = '1212'
        and status = 1)
union
select user_id2 as friends_of_friends
  from Friends f1
  where f1.user_Id1 in (
      select user_Id1 as my_friends_userId
        from Friends f
        where f.user_Id2 = '1212'
          and status = 1
      union
      select user_Id1 as my_friends_userId
        from Friends f
        where f.user_Id1 = '1212'
          and status = 1);

然后為我自己的朋友和我已屏蔽的朋友添加排除對象,它變為:

select f1.user_id1 as friends_of_friends
from Friends f1
where f1.user_Id2 in (select user_Id1 as my_friends_userId  /* sub-query for friends of friends */
      from Friends f
      where f.user_Id2 = '1212'
        and status = 1
      union
      select user_Id2 as my_friends_userId
      from Friends f
      where f.user_Id1 = '1212'
        and status = 1)
and f1.user_id1 not in   /* exclusion of my own friends */
(select user_Id1 as my_friends_userId
      from Friends f
      where f.user_Id2 = '1212'
        and status = 1
      union
      select user_Id2 as my_friends_userId
      from Friends f
      where f.user_Id1 = '1212'
        and status = 1
 )
and f1.user_id1 != '1212'  /* exclusion of myself. */
and f1.user_id1 not in (select user_Id1 as my_friends_userId  /* exlusion of people I've blocked. */
      from Friends f
      where f.user_Id2 = '1212'
        and status = 3
      union
      select user_Id2 as my_friends_userId
      from Friends f
      where f.user_Id1 = '1212'
        and status = 3
 )
union  /* Now do it all over again for user_id2 */
select f2.user_id2 as friends_of_friends
from Friends f2
where f2.user_Id1 in (select user_Id1 as my_friends_userId
      from Friends f
      where f.user_Id2 = '1212'
        and status = 1
      union
      select user_Id2 as my_friends_userId
      from Friends f
      where f.user_Id1 = '1212'
        and status = 1)
and f2.user_id2 not in 
(select user_Id1 as my_friends_userId
      from Friends f
      where f.user_Id2 = '1212'
        and status = 1
      union
      select user_Id2 as my_friends_userId
      from Friends f
      where f.user_Id1 = '1212'
        and status = 1
 )
and f2.user_id2 != '1212'
and f2.user_id2 not in (select user_Id1 as my_friends_userId
      from Friends f
      where f.user_Id2 = '1212'
        and status = 3
      union
      select user_Id2 as my_friends_userId
      from Friends f
      where f.user_Id1 = '1212'
        and status = 3
 )

在每種情況下,我都是第一次標記該位置。 現在,你可以看到的混亂union的我有這個來做。 (這可能是union distinct

您不應該使用group-concat創建子句。 盡管這里很長,但速度更快。

您可以問一下各個部分的功能。 但是,我的建議是不要這樣做 這就是為什么良好的桌子設計可以使事情變得容易得多的原因。

SQL Fiddle供參考並顯示結果: http : //sqlfiddle.com/#!2/e6376/13


編輯:只是添加有關我將如何更改此架構。

目前尚不清楚在您的應用中,朋友之間的關系是Google的關系(允許非對稱關系)還是Facebook的關系(僅允許對稱關系)。

在兩種情況下,我都將架構更改為:

create table Friends (
  individual_userId int,
  friend_userId int,
  status int);

在Google中,您已經完成了。 在Facebook的情況下,我將使用此結構,但要求對於每種關系,表中都要插入兩行。 因此,如果'1212'是帶有'0415'的Facebook朋友,則存在('1212','0415')&('0415','1212')的(individual_userid,friend_userId)行。 要確保這種方法有效並得到維護,將需要用於插入/刪除的存儲過程,以確保同時添加和刪除了兩行。 (沒有更新-這些是唯一的ID。)

如果我們確定這些關系得到維護,並且開始建立關系的朋友始終存在於personal_userId中,那么我的最終查詢將變為:

select f1.friend_userId as friends_of_friends
from Friends f1
where f1.individual_userId in (   /* retrieve my friend list */
      select friend_userId as my_friends_userId
      from Friends f
      where f.individual_userId = '1212'
        and status = 1)
and f1.friend_userId not in (   /* exclusion of my own friends */
      select friend_userId as my_friends_userId
      from Friends f
      where f.individual_userId = '1212'
        and status = 1
 )
and f1.friend_userId not in ( /* exlusion of people I have blocked. */
      select friend_userId as my_friends_userId
      from Friends f
      where f.individual_userId = '1212'
        and status = 3
 )
and f1.friend_userId != '1212'  /* exclusion of myself. */

這更容易處理。 您也可以將其重寫為一系列連接,但是我懷疑第一步,使用innot in子句這樣更容易閱讀。

修改后的sqlfiddle: http ://sqlfiddle.com/#!2/92ff2/1

(我必須使用大數據集對其進行測試,但是我的直言不諱地指出聯接將更快-但是對於這樣的代碼,我懷疑學習/獲得正確的答案比最初優化速度更重要。)

正如Mike的回答所解釋的,我也是,您的表結構類似於

create table Friends (
   user_Id1 int,
   user_Id2 int,
   status int);

您似乎想要的是一個分散的朋友列表,這些列表可以是您的朋友,也可以是與您的朋友直接相關的朋友(即:與您的分離度為1)。 因此,讓我們來解決這種情況。

您的ID為1111,朋友2222和3333。

人2222的朋友為1111(您),3333(您的其他朋友)和4444(新人)。

3333人的朋友有1111(您),4444(與3333人的朋友-巧合)和5555。

現在,第二分離度(不是您要尋找的)是那個人4444的朋友是6666、7777、8888。您不在乎這些其他人(6666、7777、8888)

您正在尋找不是您的朋友的整個列表,只想查看Friends 2222、3333、4444、5555。

我將從您的朋友列表開始,並以此為基礎來獲得他們的朋友。 最內在的查詢是僅僅獲得您的不同朋友(無需硬編碼您的朋友是誰)。 然后從中得到所有的朋友。 如果它們碰巧相似,則“ DISTINCT”將為您過濾掉它們。 選擇這些對象后,獲得直接朋友的UNION來代表“ AllFriends”。 通過使用IF(),我們希望“其他”人基於聯合資格。 如果加入的人在位置1,則我們需要其他人,反之亦然。 一旦有了自己的好友列表,然后將其加入到users表中,以獲取其姓名,圖片和其他任何個人資料信息。

select
      AllFriends.FinalFriendID,
      CONCAT(U.User_FirstName, " ", U.User_LastName) AS User_FirstName, 
      U.User_ProfilePic 
   from
       ( select DISTINCT
               IF( F2.User_ID1 = YourDirectFriends.PrimaryFriend, F2.User_ID2, F2.User_ID1 ) 
                  as FinalFriendID
            from
               ( select DISTINCT 
                        IF( F.User_ID1 = YourID, F.User_ID2, F.User_ID1 ) as PrimaryFriendID
                   from
                      Friends F
                   where
                         F.user_ID1 = YourID
                      OR F.User_ID2 = YourID ) YourDirectFriends
                JOIN Friends F2
                   ON    YourDirectFriends.PrimaryFriendID = F2.User_ID1
                      OR YourDirectFriends.PrimaryFriendID = F2.User_ID2
         UNION 
         select DISTINCT
               IF( F.User_ID1 = YourID, F.User_ID2, F.User_ID1 ) as FinalFriendID
            from
               Friends F
            where
                  F.user_ID1 = YourID
               OR F.User_ID2 = YourID ) ) as AllFriends
        JOIN Users U
           on AllFriends.FinalFriendID = U.User_ID

哦,是的,在適用時添加“狀態”的限定詞和您的限制要求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM