Запрос MySQL, который выбирает не друзей пользователя

У меня есть следующая схема базы данных 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 <> ? 

И, конечно же, заполнитель — это идентификатор пользователя X.

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

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

Предоставьте образцы данных и желаемые результаты.

Infinity 22.05.2019 15:08
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
1
47
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Используя левое соединение со списком объединения:

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'

Работает прекрасно, кроме того, что возвращает еще и самого UserX. Спасибо.

Ahmed Hammad 22.05.2019 15:26

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

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 подзапросы вместе.

Я боюсь, что это возвращает только пользователей, у которых вообще нет друзей.

Ahmed Hammad 22.05.2019 16:48

@АхмедХаммад. . . Конечно, он должен проверить идентификатор, который вы хотите.

Gordon Linoff 23.05.2019 03:50

Другие вопросы по теме