如何写一个 SQL 查询 returns 所有球员的名字谁...?
How to write a SQL Query that returns all names of players who ...?
我想写一个 SQL 查询 returns Players
的所有名字 PlaysMatches
和他们认识的每个人。
有3个table:
玩家(ID、姓名)
知道(ID,Player1_ID,Player2_ID)
PlaysMatches (ID, Player1_ID, Player2_ID)
其中 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 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:查询也会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 上可能会失败。
我想写一个 SQL 查询 returns Players
的所有名字 PlaysMatches
和他们认识的每个人。
有3个table:
玩家(ID、姓名)
知道(ID,Player1_ID,Player2_ID)
PlaysMatches (ID, Player1_ID, Player2_ID)
其中 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 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:查询也会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 上可能会失败。