在此方案中我有3个表:Teams
,Players
和PlayersInTeams
。
Player
只是注册用户。没有W / L数据与Player
相关联。
Team
维持赢/输记录。如果玩家自己玩,那么他就会玩他的独奏"团队(Team
只有该玩家)。每次Bob和Jan一起获胜时,他们的Team
条目都会获得胜利++。每次杰森和汤米一起输球时,他们的球队入场都会有损失++。
PlayersInTeams
表只有2列,它是Players
和Teams
之间的交集表:
> desc PlayersInTeams ;
+------------+---------+
| Field | Type |
+------------+---------+
| fkPlayerId | int(11) |
| fkTeamId | int(11) |
+------------+---------+
所以这是困难的部分:
由于Player
可以是多个Teams
的一部分,因此在匹配开始时从TeamId
表中获取正确的Teams
非常重要。
玩家的SOLO团队由
提供select fkTeamId from PlayersInTeams where
fkPlayerId=1 HAVING count(fkTeamId)=1;
不,不!但我不明白为什么。
我试图说:
从PlayersInTeams获取fkTeamId fkPlayerId = 1,还有行数
具有此特定fkTeamId的正好是1。
查询返回(空集),实际上如果我将HAVING子句更改为不正确(HAVING count(fkTeamId)<>1;
),它将返回我想要的行。
答案 0 :(得分:3)
要修复您的查询,请添加group by
。要计算每个团队的计数,您需要更改where
子句以返回玩家1所在的所有团队:
select fkTeamId
from PlayersInTeams
where fkTeamId in
(
select fkTeamId
from PlayersInTeams
where fkPlayerId = 1
)
group by
fkTeamId
having count(*) = 1;
下面详细解释为什么您的count(*) = 1
条件以令人惊讶的方式运作。当查询包含类似count
的聚合但没有group by
子句时,数据库会将整个结果集视为一个组。
在MySQL以外的数据库中,如果没有聚合,则无法选择不在group by
的列。在MySQL中,所有这些列都返回数据库遇到的第一个值(实际上是组中的随机值)。
create table YourTable (player int, team int);
insert YourTable values (1,1), (1,2), (2,2);
select player
, team
, count(team)
from YourTable
where player = 2
- &GT;
player team count(team)
1 1 1
前两列来自player = 1
的随机行。 count(team)
值为2,因为有两行player = 1
和非空team
。伯爵对球队中球员的数量一无所知。
答案 1 :(得分:2)
最自然的事情是计算行数以查看正在发生的事情:
select fkTeamId, count(*)
from PlayersInTeams
where fkPlayerId=1
group by fkTeamId;
group by
子句是编写查询的更自然的方式:
select fkTeamId
from PlayersInTeams
where fkPlayerId=1
having count(fkteamid) = 1
但是,如果播放器只有一行,那么原始版本应该有效 - 过滤会将其带到一行,fkTeamId将成为行中的团队,而having
将是满意。一种可能是数据中有重复的行。
如果重复是个问题,您可以这样做:
select fkTeamId
from PlayersInTeams
where fkPlayerId=1
having count(distinct fkteamid) = 1
编辑“solo team”:
正如Andomar所指出的, solo 团队的定义并不完全符合我的预期。这是球员中唯一的球员。因此,要获得给定玩家是团队的团队列表:
select fkTeamId
from PlayersInTeams
group by fkTeamId
having sum(fkPlayerId <> 1) = 0
也就是说,您无法过滤掉其他玩家并希望获得此信息。你特别需要他们,以确保他们不在团队中。
如果你想要所有独奏团队:
select fkTeamId
from PlayersInTeams
group by fkTeamId
having count(*) = 1
答案 2 :(得分:1)
HAVING
通常与GROUP BY
语句一起使用 - 就像WHERE
一样,它会应用于分组数据。
SELECT fkTeamId
FROM PlayersInTeams
WHERE fkPlayerId = 1
GROUP BY fkTeamId
HAVING COUNT(fkPlayerId) = 1
答案 3 :(得分:1)
SqlFiddle:http://sqlfiddle.com/#!2/36530/21
尝试首先找到一个玩家的团队,然后使用它来查找玩家ID,如果他们在任何一个团队中:
select DISTINCT PlayersInTeams.fkTeamId
from (
select fkTeamId
from PlayersInTeams
GROUP BY fkTeamId
HAVING count(fkPlayerId)=1
) AS Sub
INNER JOIN PlayersInTeams
ON PlayersInTeams.fkTeamId = Sub.fkTeamId
WHERE PlayersInTeams.fkPlayerId = 1;
答案 4 :(得分:0)
这里的每个人的答案都非常有帮助。除了遗漏GROUP BY
之外,我发现我的问题主要是我的WHERE
条款“太早”。
说我们有
insert into PlayersInTeams values
(1, 1), -- player 1 is in solo team id=1
(1, 2),(2,2) -- player 1&2 are on duo team id=2
;
现在我们尝试:
select fkTeamId from PlayersInTeams
where fkPlayerId=1 -- X kills off data we need
group by fkTeamId
HAVING count(fkTeamId)=1;
特别是WHERE
正在过滤临时结果集,以便从结果集中删除没有 fkPlayerId=1
的任何行。由于每个fkPlayerId只与每个fkTeamId相关联一次,当然fkTeamId出现次数的COUNT总是为1.所以你总是得到一个团队列表 player 1是的一部分,但是你仍然不认识他的SOLO团队。
戈登回答我的附录
select fkPlayerId,fkTeamId
from PlayersInTeams
group by fkTeamId
having count(fkTeamId) = 1
and fkPlayerId=1 ;
特别好,因为它是一个便宜的查询,并做我们想要的。它选择所有SOLO团队第一,(选择所有仅在表中发生ONCE的fkTeamIds(通过HAVING count(*)=1
)),然后从那里我们去说,“好吧,现在给我一个有这个fkPlayerId = 1的那个”。瞧,独立团队。