Ваш вопрос можно перевести на: Найти всех игроков, которые могут сказать: «Я не знаю ни одного игрока, против которого я не играл».Это очень похоже на Джо Селко: «В этом ангаре нет самолетов, на которых я не могу летать!»от Разделенное мы стоим: SQL реляционного разделения .Есть несколько способов ответить на вопрос с помощью SQL.В вашем случае я бы использовал следующее:
select p.name
from Players p
left join Knows k on k.Player1_ID = p.ID
left join PlaysMatches m
on m.Player1_ID = k.Player1_ID
and m.Player2_ID = k.Player2_ID
group by p.name
having sum(k.Player2_ID is not null and m.Player2_ID is null) = 0
Все игроки (слева) объединены с игроками, которых они знают.Второе (левое) соединение найдет соответствующие совпадения.Если совпадений не найдено, условие k.Player2_ID is not null and m.Player2_ID is null
будет ИСТИНА.Прочитайте это как «Я знаю Player2 (k.Player2_ID is not null
), но я никогда не играл против него / нее (m.Player2_ID is null
)».Если это условие TRUE для любого Player2 из таблицы Knows
, SUM(..)
будет > 0
.
Примечание:
sum(k.Player2_ID is not null and m.Player2_ID is null) = 0
работает в MySQLпотому что логическое выражение возвращает 0
или 1
(или NULL
, но не в этом случае).Если вы хотите, чтобы он соответствовал стандарту, используйте:
sum(case when k.Player2_ID is not null and m.Player2_ID is null then 1 else 0 end) = 0
Примечание 2: Запрос также вернет всех игроков, которые никого не знают.Если вы не хотите этого, замените первое соединение слева на внутреннее соединение.Вы также можете изменить условие HAVING на
having sum(m.Player2_ID is null) = 0
, поскольку k.Player2_ID is not null
всегда верно для ВНУТРЕННЕГО СОЕДИНЕНИЯ.
Примечание 3: Также может быть другое условие HAVING:
having count(distinct k.Player2_ID) = count(distinct m.Player2_ID)
Примечание 4: Для лучшей производительности я бы использовал group by p.ID
вместо group by p.name
.Это должно работать на большинстве конфигураций MySQL.Но может произойти сбой на MariaDB с включенным ONLY_FULL_GROUP_BY
.