[英]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是我的朋友,我試圖讓他們的所有朋友都很好,但我想要的是:
如果通過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. */
這更容易處理。 您也可以將其重寫為一系列連接,但是我懷疑第一步,使用in
和not 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.