如何编写一个SQL查询来返回...的所有玩家的姓名?

时间:2019-04-27 12:02:41

标签: mysql relational-division

我想编写一个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 个答案:

答案 0 :(得分:1)

我认为您可以通过逆转当前查询的逻辑来达到我的理解。即要求玩家找到unsigned int中没有匹配记录的地方。

%hhx

答案 1 :(得分:0)

您的问题可以转换为:查找所有可以说“我不认识没有与之对抗的球员”的球员。这与乔·塞尔科(Joe Celko)的“机库中没有我不能飞的飞机!”非常相似。来自Divided We Stand: The SQL of Relational Division。使用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。读为“我知道Player2(k.Player2_ID is not null),但我从未与他/她(m.Player2_ID is null)对抗。如果对于Knows表中的任何Player2,此条件为TRUE,则SUM(..)将为> 0

注意:

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

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

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

注意2:该查询还将返回所有不认识的玩家。如果您不希望这样做,请将第一个LEFT JOIN更改为INNER JOIN。您还可以将HAVING子句更改为

having sum(m.Player2_ID is null) = 0

因为k.Player2_ID is not null对于内部联接始终为真。

注意3:另一个可能发生的情况是:

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上可能会失败。