我尝试使用下表计算球队中每位球员的进球数和助攻数。一名球员可以在一个赛季中参加多支球队比赛。我的结果计算了所有球队的总助攻数。我怎样才能将助攻限制在一支球队?
我的查询包含在下面。我期待的结果是Gretzky的2个进球和1个助攻。我不希望结果中包含辅助ID 3.
mysql> select * from players;
+----+------------+-----------+
| id | first_name | last_name |
+----+------------+-----------+
| 1 | Wayne | Gretzky |
| 2 | Mario | Lemieux |
| 3 | Mark | Messier |
+----+------------+-----------+
mysql> select * from teams;
+----+-----------+
| id | team_name |
+----+-----------+
| 1 | Oilers |
| 2 | Penguins |
| 3 | Kings |
+----+-----------+
mysql> select * from goals;
+----+-----------+---------+---------+
| id | player_id | team_id | game_id |
+----+-----------+---------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 1 |
| 3 | 3 | 1 | 1 |
| 4 | 2 | 2 | 1 |
| 5 | 3 | 3 | 2 |
+----+-----------+---------+---------+
mysql> select * from assists;
+----+---------+-----------+
| id | goal_id | player_id |
+----+---------+-----------+
| 1 | 1 | 3 |
| 2 | 3 | 1 |
| 3 | 5 | 1 |
+----+---------+-----------+
mysql> select players.id, players.last_name,
-> count(distinct goals.id) as 'Goals',
-> count(distinct assists.id) as 'Assists'
-> from players
-> join goals on players.id = goals.player_id
-> left join assists on players.id = assists.player_id
-> join teams on goals.team_id = teams.id
-> where teams.id = 1
-> group by players.id;
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
| 1 | Gretzky | 2 | 2 |
| 3 | Messier | 1 | 1 |
+----+-----------+-------+---------+
答案 0 :(得分:1)
我认为,您尝试做的最直接的方法是使用相关的子查询。
所以,下面的第一个示例会返回您正在寻找的结果。您可以轻松修改它以排除零目标和助攻的行。
它在每个子查询中使用team_id值,但您可以使用变量或参数提供它,如图所示,这样您只需要指定一次值:
set @team_id := 2;
select
p.id as player_id
, p.last_name
, (
select count(*)
from goals
where player_id = p.id
and team_id = @team_id
) as goals
, (
select count(*)
from assists
inner join goals on assists.goal_id = goals.id
where assists.player_id = p.id
and goals.team_id = @team_id
) as assists
from players p
对于第1队:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
| 1 | Gretzky | 2 | 1 |
| 2 | Lemieux | 0 | 0 |
| 3 | Messier | 1 | 1 |
+----+-----------+-------+---------+
对于第2队:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
| 1 | Gretzky | 0 | 0 |
| 2 | Lemieux | 1 | 0 |
| 3 | Messier | 0 | 0 |
+----+-----------+-------+---------+
对于第3队:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
| 1 | Gretzky | 0 | 1 |
| 2 | Lemieux | 0 | 0 |
| 3 | Messier | 1 | 0 |
+----+-----------+-------+---------+
<强>后记强>
从使用较少的子查询和/或使用聚合查询尝试执行此操作的角度来看,第一次尝试时会遇到一些问题。
一个问题是,如果你不包含group by
子句中的所有字段,你的查询可能无法正常工作,即使MySQL不会抱怨你(大多数?)其他数据库会。
另外,因为你的助攻和球员表中的记录只是通过目标表与球队间接相关,所以很难通过一个查询获得目标和助攻的独立汇总。
作为一种类型的例证,其他早期的答案,包括我的第一次快速拍摄,有几个问题:
如果玩家有团队助攻,但该团队没有任何目标,则查询无法返回该玩家和团队组合的任何结果。结果不完整。
如果一名球员有一支球队的进球,但该球队没有任何助攻,那么当他们应该返回零时,查询仍然会返回一个正数助攻。 结果实际上是错误的,而不仅仅是不完整的。
下面是一个稍微更正确,但仍然不完整的解决方案。它正确地指示一个玩家是否没有助攻,虽然返回null而不是0,这是不幸的。
但这仍然是一个部分解决方案,因为如果一名球员没有球队的任何进球,你仍然不会看到该球员和球队组合的任何助攻。
这使用子查询作为虚拟表来聚合每个玩家和团队的助攻,而左外部联接到子查询是因为如果有目标但没有助攻则返回结果。
select
p.id as player_id
, p.last_name
, count(g.game_id) as goals
, a.assists
from players p
inner join goals g on p.id = g.player_id
left join (
select
assists.player_id
, goals.team_id
, count(assists.id) as assists
from assists
inner join goals on assists.goal_id = goals.id
group by player_id, team_id, assists.id
) a
on g.player_id = a.player_id and g.team_id = a.team_id
where g.team_id = 1
group by player_id, last_name, g.team_id
该查询返回以下结果:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
| 1 | Gretzky | 2 | 1 |
| 3 | Messier | 1 | 1 |
+----+-----------+-------+---------+
为第2队运行这个,你得到了下一个结果,表明Lemieux没有为2队提供任何助攻,但是对于其他两名没有助攻且没有球队进球的球员都没有任何结果2:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
| 2 | Lemieux | 1 | null |
+----+-----------+-------+---------+
最后,为第3队运行它,你得到了下一个结果,表明Messier没有任何球队3的任何助攻。但Gretzky失踪了,尽管他确实为3队提供了助攻,因为他没有团队3没有任何目标。所以解决方案不完整:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
| 3 | Messier | 1 | null |
+----+-----------+-------+---------+