MySQL 选择用户非朋友的查询
MySQL query that selects non-friends of a user
我有以下 Mysql 数据库模式:
User(Id, FirstName, LastName, NickName, Etc.)
Request(SenderId, ReceiverId)
Friendship(Id1, Id2)
我认为友谊是一种无向关系,这意味着对于每一个友谊,我都会将它插入两次友谊table。 (如果这不是一个好主意,请告诉我)。
我要检索的是一个用户列表,这些用户不是特定用户的朋友(让我将他命名为 UserX),也没有正在进行的当前请求 to/from 他。
我最初的尝试让我想到了这个:
SELECT User.Id, User.NickName, User.Picture FROM User
LEFT JOIN Friendship A ON User.Id = A.Id1
LEFT JOIN Friendship B ON User.Id = B.Id2
LEFT JOIN Request C ON User.Id = C.Sender
LEFT JOIN Request D ON User.Id = D.Reciever
WHERE User.Id <> ?
而且,占位符当然是 UserX 的 Id。
这行不通,因为虽然删除了与 UserX 有友谊或请求的元组,但朋友仍然出现,因为他们与其他用户有友谊!
提前致谢。
对联合列表使用左连接:
select *
from User u1
left join
(
select ID2 as id
from Friendships
where ID1 = 'UserX'
union all
select ID1
from Friendships
where ID2 = 'UserX'
union all
select Sender
from Request
where Receiver = 'UserX'
union all
select Receiver
from Request
where Sender = 'UserX'
) ux
on ux.id = u1.id
where ux.id is null
and ux.id <> 'UserX'
如果您从 table "request" 和 "Friendship" 中收集所有不同的 ID,然后从上面列表中不可用的用户 ID 中收集 select 条记录怎么办。
SELECT Id, FirstName, LastName, NickName
FROM User
WHERE ID NOT IN
(
SELECT DSTINCT Id1 ID FROM Friendship
UNION
SELECT DSTINCT Id2 FROM Friendship
UNION
SELECT DSTINCT SenderId FROM Request
UNION
SELECT DSTINCT ReceiverId FROM Request
)A
如果你想要一个高效的解决方案,请多次使用not exists
:
select u.*
from user u
where not exists (select 1 from friendship f where f.id1 = u.id and f.id2 = ?) and
not exists (select 1 from friendship f where f.id2 = u.id and f.id1 = ?) and
not exists (select 1 from request r where r.SenderId = u.id and r.ReceiverId = ?) and
not exists (select 1 from request r where r.ReceiverId = u.id and r.SenderId = ?);
特别是,这可以利用以下索引:
friendship(id1, id2)
friendship(id2, id1)
request(SenderId, ReceiverId)
request(ReceiverId, SenderId)
这应该比 union
一起子查询的解决方案有更好的性能。
我有以下 Mysql 数据库模式:
User(Id, FirstName, LastName, NickName, Etc.)
Request(SenderId, ReceiverId)
Friendship(Id1, Id2)
我认为友谊是一种无向关系,这意味着对于每一个友谊,我都会将它插入两次友谊table。 (如果这不是一个好主意,请告诉我)。
我要检索的是一个用户列表,这些用户不是特定用户的朋友(让我将他命名为 UserX),也没有正在进行的当前请求 to/from 他。
我最初的尝试让我想到了这个:
SELECT User.Id, User.NickName, User.Picture FROM User
LEFT JOIN Friendship A ON User.Id = A.Id1
LEFT JOIN Friendship B ON User.Id = B.Id2
LEFT JOIN Request C ON User.Id = C.Sender
LEFT JOIN Request D ON User.Id = D.Reciever
WHERE User.Id <> ?
而且,占位符当然是 UserX 的 Id。
这行不通,因为虽然删除了与 UserX 有友谊或请求的元组,但朋友仍然出现,因为他们与其他用户有友谊!
提前致谢。
对联合列表使用左连接:
select *
from User u1
left join
(
select ID2 as id
from Friendships
where ID1 = 'UserX'
union all
select ID1
from Friendships
where ID2 = 'UserX'
union all
select Sender
from Request
where Receiver = 'UserX'
union all
select Receiver
from Request
where Sender = 'UserX'
) ux
on ux.id = u1.id
where ux.id is null
and ux.id <> 'UserX'
如果您从 table "request" 和 "Friendship" 中收集所有不同的 ID,然后从上面列表中不可用的用户 ID 中收集 select 条记录怎么办。
SELECT Id, FirstName, LastName, NickName
FROM User
WHERE ID NOT IN
(
SELECT DSTINCT Id1 ID FROM Friendship
UNION
SELECT DSTINCT Id2 FROM Friendship
UNION
SELECT DSTINCT SenderId FROM Request
UNION
SELECT DSTINCT ReceiverId FROM Request
)A
如果你想要一个高效的解决方案,请多次使用not exists
:
select u.*
from user u
where not exists (select 1 from friendship f where f.id1 = u.id and f.id2 = ?) and
not exists (select 1 from friendship f where f.id2 = u.id and f.id1 = ?) and
not exists (select 1 from request r where r.SenderId = u.id and r.ReceiverId = ?) and
not exists (select 1 from request r where r.ReceiverId = u.id and r.SenderId = ?);
特别是,这可以利用以下索引:
friendship(id1, id2)
friendship(id2, id1)
request(SenderId, ReceiverId)
request(ReceiverId, SenderId)
这应该比 union
一起子查询的解决方案有更好的性能。