如何写一个 SQL 查询 returns 所有球员的名字谁...?

How to write a SQL Query that returns all names of players who ...?

我想写一个 SQL 查询 returns Players 的所有名字 PlaysMatches 和他们认识的每个人。

有3个table:

其中 table Knows 暗示 Player1 知道 Player2,而 table PlaysMatches 暗示 Player1 玩比赛Player2.

我的查询问题是 returns 与至少一名他们认识的球员进行比赛的球员姓名,而不是他们认识的所有人。

我应该如何更改我的查询以使其显示他们认识的每个人部分?

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

我认为您可以通过反转当前查询的逻辑来实现我所理解的您想要的。 IE。询问 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));

你的问题可以翻译成:找到所有可以说 "I know no player who I didn't play against" 的玩家。这与来自 Divided We Stand: The SQL of Relational Division 的 Joe Celko 的 "There ain’t no planes in this hangar that I can’t fly!" 非常相似。用 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 将为 TRUE。读作 "I know Player2 (k.Player2_ID is not null) but I never played against him/her (m.Player2_ID is null)"。如果此条件对于 Knows table 中的任何 Player2 为真,则 SUM(..) 将是 > 0

注:

sum(k.Player2_ID is not null and m.Player2_ID is null) = 0

在 MySQL 中有效,因为布尔表达式 returns 01(或 NULL,但在这种情况下不是)。如果您希望它符合标准,请使用:

sum(case when k.Player2_ID is not null and m.Player2_ID is null then 1 else 0 end) = 0

注2:查询也会return所有不认识的玩家。如果您不想这样,请将第一个 LEFT JOIN 更改为 INNER JOIN。您还可以将 HAVING 子句更改为

having sum(m.Player2_ID is null) = 0

因为 k.Player2_ID is not null 对于 INNER JOIN 总是正确的。

注3:另一个HAVING条件也可以是:

having count(distinct k.Player2_ID) = count(distinct m.Player2_ID)

注 4: 为了获得更好的性能,我会使用 group by p.ID 而不是 group by p.name。这应该适用于大多数 MySQL 配置。但在启用 ONLY_FULL_GROUP_BY 的 MariaDB 上可能会失败。