MySQL запрос, который выбирает не друзей пользователя - PullRequest
0 голосов
/ 22 мая 2019

У меня есть следующая схема базы данных Mysql:

User(Id, FirstName, LastName, NickName, Etc.)
Request(SenderId, ReceiverId)
Friendship(Id1, Id2)

Я считаю дружбу неориентированным отношением, что означает, что для каждой дружбы я вставляю ее дважды вСтол дружбы.(Дайте мне знать, если это не очень хорошая идея, пожалуйста.)

Я пытаюсь получить список пользователей, которые не являются друзьями определенного пользователя (позвольте мне назвать его UserX), нитекущий запрос к нему / от него.

Мои первоначальные испытания привели меня к следующему:

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.

Thisне работает, потому что, хотя кортежи, у которых есть дружеские отношения или запросы с UserX, удаляются, друзья все равно появляются, потому что они дружат с другими пользователями!

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 22 мая 2019

Если вы хотите эффективное решение, используйте 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 подзапрашивают вместе.

1 голос
/ 22 мая 2019

Использование левого присоединения к списку объединений:

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'
0 голосов
/ 22 мая 2019

Что если вы соберете все отдельные идентификаторы из таблицы «запрос» и «Дружба», а затем выберете записи из идентификатора пользователя, которого нет в приведенном выше списке.

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
...