我想编写一个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))
答案 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中有效,因为布尔表达式返回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:该查询还将返回所有不认识的玩家。如果您不希望这样做,请将第一个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上可能会失败。