Как написать SQL-запрос, который возвращает все имена игроков, которые ...? - PullRequest
1 голос
/ 27 апреля 2019

Я хочу написать SQL-запрос, который возвращает все имена Players кто PlaysMatches со всеми, кого они знают.

Есть 3 таблицы:

  • Игроки (ID, имя)

  • Знает (ID, Player1_ID, Player2_ID)

  • PlaysMatches (ID, Player1_ID, Player2_ID)

Где таблица Knows подразумевает, что Player1 знает Player2, а таблица PlaysMatches подразумевает, что Player1 играет совпадение с Player2.

Моя проблема с моим запросом состоит в том, что он возвращает имена игроков, которые играют матч по крайней мере с одним знакомым игроком, а не со всеми, кого они знают.

Что я должен изменить в своем запросе, чтобы он отображал часть, которую они знают?

    SELECT DISTINCT P1.name
    FROM Players P1, Players P2
    WHERE (EXISTS (SELECT *
                FROM  PlaysMatches PL
                WHERE P1.id = PL.Player1_id AND P2.id = PL.Player2_id)
                AND EXISTS (SELECT *
                            FROM Knows K
                            WHERE P1.id = K.Player1_id AND P2.id = K.Player2_id))

Ответы [ 2 ]

1 голос
/ 27 апреля 2019

Я думаю, что вы можете достичь того, что, как я понимаю, вы хотите, изменив логику вашего текущего запроса.Т.е. попросите игроков, у которых в knows нет записей, для которых не найдено ни одного совпадения.

SELECT p.name
       FROM players p
       WHERE NOT EXISTS (SELECT *
                                FROM knows k
                                WHERE p.id IN (k.player1_id,
                                               k.player2_id)
                                      AND NOT EXISTS (SELECT *
                                                             FROM playsmatches pm
                                                             WHERE pm.player1_id = k.player1_id
                                                                   AND pm.player2_id = k.player2_id
                                                                    OR pm.player1_id = k.player2_id
                                                                       AND pm.player2_id = k.player1_id));
0 голосов
/ 27 апреля 2019

Ваш вопрос можно перевести на: Найти всех игроков, которые могут сказать: «Я не знаю ни одного игрока, против которого я не играл».Это очень похоже на Джо Селко: «В этом ангаре нет самолетов, на которых я не могу летать!»от Разделенное мы стоим: 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.

...