我正在asp.net c#中设计一个简单的社交网站,我需要一个帮助来查询查询中的共同朋友。
我的表是:
寄存器:
朋友:
在Friends
表中, MyId 和 FriendId 都是用户的ID。不同之处在于显示谁先与另一个人建立友谊。
我尝试写下面的一些查询,但它无法正常工作。
查询示例:
Select count(*)
from Register R
where RegisterId in (
(select F.FriendId as RegisterId
from Friends f
where f.MyId='" + Session["UserId"] + "' and f.Status=1)
Union
(select F.MyId as RegisterId
from Friends f
where f.FriendId='" + Session["UserId"] + "' and f.Status=1)
union
(select F.FriendId as RegisterId
from Friends f
where f.MyId='" + Session["UserId"] + "' and f.Status=1)
union
(select F.FriendId as RegisterId
from Friends f
where f.MyId='" + Session["UserId"] + "' and f.Status=1)
)
and R.RegisterId !='" + Session["UserId"] + "'
and R.RegisterId !='" + Session["CurrentProfileId"] + "'
答案 0 :(得分:2)
所以,共同的朋友,你的意思是,如果爱丽丝知道鲍勃,而爱丽丝知道查理,那么你想要识别鲍勃&查理是潜在的朋友,因为他们在爱丽丝中有共同的朋友?
在视觉上,我们可以将其表示为:
Bob <==> Alice
其中&lt; ==&gt;表示Friends
表中的条目。同样:
Charlie <==> Alice
爱丽丝对两个友谊都很常见,所以:
Bob <==> Alice <==> Charlie
使用上面的视觉表示,您会注意到有两个&lt; ==&gt;符号,表示正在运行的Friends
表有2个实例(别名)。
我们称他们为FriendLeft
和FriendRight
。在字段MyId
上加入这两个表,但要确保左表和右表之间的FriendId
不同。如下面的查询:
select
RegisterLeft.RegisterId as PotentialFriend1Id
, RegisterLeft.Name as PotentialFriend1Name
, RegisterRight.RegisterId as PotentialFriend2Id
, RegisterRight.Name as PotentialFriend2Name
, MutualFriend.Name as MutualFriendName
from ##Register as RegisterLeft
inner join ##Friends as FriendLeft
on RegisterLeft.RegisterId = FriendLeft.FriendId
inner join ##Friends as FriendRight
on FriendLeft.MyId = FriendRight.MyId -- join left and right instances of the friendship table
inner join ##Register as RegisterRight
on FriendRight.FriendId = RegisterRight.RegisterId
inner join ##Register as MutualFriend
on FriendLeft.MyId = MutualFriend.RegisterId
where FriendLeft.FriendId != FriendRight.FriendId -- but eliminate rows that return the same person
对于给定的样本数据:
create table ##Register
(
RegisterId int
, Name varchar(50)
)
go
insert into ##Register values (1, 'Alice')
insert into ##Register values (2, 'Bob')
insert into ##Register values (3, 'Charlie')
go
create table ##Friends
(
MyId int
, FriendId int
)
go
insert into ##Friends values (1, 2) -- Alice <==> Bob
insert into ##Friends values (1, 3) -- Alice <==> Charlie
insert into ##Friends values (2, 1) -- Bob <==> Alice
insert into ##Friends values (3, 1) -- Charlie <==> Alice
go
我们得到的结果是:
PotentialFriend1Id PotentialFriend1Name PotentialFriend2Id PotentialFriend2Name MutualFriendName
------------------ --------------------- ------------------ --------------------- -----------------
3 Charlie 2 Bob Alice
2 Bob 3 Charlie Alice
以上正确地将Bob和Charlie视为爱丽丝作为共同朋友的潜在朋友。
请注意我在Friends
表格中输入数据的方式 - 我已经反映了两种方式将友谊视为可交换的关系,因此一对(1, 2)
是由等效的(2, 1)
匹配。这使查询更简单。
这也意味着结果为你提供了两行潜在的友谊 - 正如我们上面所见,我们得到(Bob, Charlie)
和(Charlie, Bob)
的结果,这基本上是潜在的友谊。鉴于您正在为Bob或Charlie运行此查询(以显示&#34;您可能知道的人的列表&#34;),无论如何您将在字段PotentialFriend1Id
上进行过滤。如果您不是,那么您可以通过添加一个子句来确保PotentialFriend1Id
小于(或大于)PotentialFriend2Id
来消除这种倍增。这两种情况都会删除加倍的结果。
如果您不希望在Friends
表格中存储两行,以表示单个友谊以表示每个方向的友谊,那么您的查询将依赖于添加朋友的顺序,以及识别共同的朋友变得更加困难。在这种情况下,创建反映关系的视图可能更容易:
CREATE VIEW FriendsReflected AS
SELECT MyId, FriendId FROM Friends
UNION
SELECT FriendId, MyId FROM Friends
这样,如果Friends
仅包含{ (1, 2) ; (1, 3) }
,则视图将返回{ (1, 2) ; (1, 3) ; (2, 1) ; (3, 1) }
。
您已经在下面澄清过,如果Bob与Alice和Charlie都是朋友,如果David是Bob的朋友,那么David应该看到Alice和Charlie,他们是David的朋友Bob的朋友。
给出以下样本数据:
insert into ##Register values (1, 'Alice')
insert into ##Register values (2, 'Bob')
insert into ##Register values (3, 'Charlie')
insert into ##Register values (4, 'David')
go
insert into ##Friends values (1, 2) -- Alice <==> Bob
insert into ##Friends values (3, 2) -- Charlie <==> Bob
insert into ##Friends values (2, 1) -- Bob <==> Alice
insert into ##Friends values (2, 3) -- Bob <==> Charlie
insert into ##Friends values (2, 4) -- Bob <==> David
insert into ##Friends values (4, 2) -- David <==> Bob
go
这模仿以下关系,大卫是鲍勃的朋友,鲍勃是爱丽丝和查理的朋友:
David <==> Bob <==> Alice
David <==> Bob <==> Charlie
然后,以下查询是您需要的:
select
Myself.Name as Myself
, MyFriendsDetails.Name as MyFriend
, TheirFriendDetails.Name as MyFriendsFriends
from ##Register as Myself
inner join ##Friends as MyFriends
on Myself.RegisterId = MyFriends.MyId
inner join ##Register as MyFriendsDetails
on MyFriends.FriendId = MyFriendsDetails.RegisterId
inner join ##Friends as TheirFriends
on MyFriends.FriendId = TheirFriends.MyId
inner join ##Register as TheirFriendDetails
on TheirFriends.FriendId = TheirFriendDetails.RegisterId
where Myself. RegisterId != TheirFriendDetails.RegisterId -- Remove cases where the friend's friend is myself
因为它返回以下结果,其中第一列显示为个人,第二列显示为他/她的朋友,第三列显示为朋友的朋友。最后两行专门展示了David的情况。然而,总的来说,鲍勃是一个明星的中心,有三个链接到他的3个朋友,爱丽丝,查理和大卫。通过Bob,他们每个都暴露给另外2个,这就是为什么结果总共有6行。
Myself MyFriend MyFriendsFriends
------------- ------------- --------------------
Alice Bob Charlie
Alice Bob David
Charlie Bob Alice
Charlie Bob David
David Bob Alice
David Bob Charlie