MySQL计算多个分组列的行数

时间:2015-04-17 18:06:47

标签: mysql

我在MySQL表上有以下结构:

-------------------------------------------
                 Goal
-------------------------------------------
GoalID  |  GameID  |  ScorerID  |  AssistID
-------------------------------------------
   1          1          1            2
   2          1          2            3
   3          1          2           null
   4          1          3            2
   5          2          1            3
   6          2          1           null


----------------------
       Player
----------------------
PlayerID  |  LastName
----------------------
   1            AB    
   2            CD  
   3            EF  

现在,我想要实现的目标如下:

-------------------------------------------
GameID  |  Player  |  Goals  |  Assists
-------------------------------------------
   1         AB          1         0
   1         CD          2         2
   1         EF          1         1
   2         AB          2         0
   2         EF          0         1

这是我尝试的但它给了我错误的结果:

SELECT Goal.GoalID,
   Goal.GameID,
   COUNT(Scorer.PlayerID) AS Goals,
   COUNT(Assist.PlayerID) AS Assists,
   Player.LastName AS Player
FROM Goal
LEFT JOIN Player Player
       ON Player.PlayerID = Goal.ScorerID
       OR Player.PlayerID = Goal.AssistID
LEFT JOIN Player Scorer
       ON Scorer.PlayerID = Goal.ScorerID
LEFT JOIN Player Assist
       ON Assist.PlayerID = Goal.AssistID
GROUP BY Player,
         Goal.GameID
ORDER BY Goal.GameID,
         Goal.GoalID

我非常确定这是获得结果的简单方法,但我无法理解这一点。

5 个答案:

答案 0 :(得分:3)

您可以使用条件聚合来完成此任务。为此,您在玩家ID与scorerid或辅助ID匹配的条件下加入玩家和目标表,然后获得玩家ID在分数或辅助列中的情况的SUM(),并最终分组gameID和playerID。像这样:

SELECT g.gameID, p.lastName AS Player, SUM(g.scorerID = p.playerID) AS goals, SUM(g.assistID = p.playerID) AS assists
FROM goal g
JOIN player p ON p.playerID = g.scorerID OR p.playerID = g.assistID
GROUP BY g.gameID, p.playerID;

以下是SQL Fiddle示例。

重要的是要注意,此示例假设玩家至少有一个目标或至少一个助手。如果你想要两个都没有的玩家,你可以使用外部联接。

答案 1 :(得分:2)

http://sqlfiddle.com/#!9/88479/7

SELECT g.GameID, 
  p.LastName, 
  SUM(IF(p.id=g.ScorerID,1,0)) as Goals, 
  SUM(IF(p.id=g.AssistID,1,0)) as Assists
FROM goal g
LEFT JOIN player p
ON p.id = g.ScorerID
  OR p.id = g.AssistID
GROUP BY g.GameID,p.id

答案 2 :(得分:1)

解决此问题的另一种方法是CROSS JOIN玩家和目标,然后使用Scorers映射计算AssistsCASE..WHEN上的交叉点数量。 HAVING用于消除那些没有为得分线做出贡献的球员。

SELECT
   Goal.GameID,
   Player.LastName AS Player,
   SUM(CASE WHEN Goal.ScorerId = Player.PlayerID THEN 1 ELSE 0 END) AS Goals,
   SUM(CASE WHEN Goal.AssistId = Player.PlayerID THEN 1 ELSE 0 END) AS Assists
FROM Goal
CROSS JOIN Player
GROUP BY Player.LastName,
         Goal.GameID
HAVING Goals > 0 OR Assists > 0
ORDER BY Goal.GameID,
         Player.LastName;

SqlFiddle here

答案 3 :(得分:0)

有几种方法可以解决这个问题。我相信这样的事情会很好:

SELECT
    GameId,
    Lastname,
    Sum(Goals) as Goals,
    Sum(Assists) as Assists
FROM
    (
        SELECT GameID, Player.Lastname, 1 as Goals, 0 as Assists
        FROM Goal 
            INNER JOIN Player ON goal.scorerID = Player.PlayerID

        UNION

        SELECT GameID, Player.Lastname, 0 as Goals, 1 as Assists
        FROM Goal 
            INNER JOIN Player ON goal.AssistID = Player.PlayerID

    ) Games
GROUP BY GameID, LastName

答案 4 :(得分:0)

这是实现这一目标的非常简单的方法:

select GameId, LastName, goals, assist
from
(
    select GameId, player, sum(goals) as goals, sum(assist) as assist
    from
    (
        select GameId, ScorerId as player, count(*) as goals, 0 as assist
        from Goal
        group by GameId, ScorerId
        union all
        select GameId, AssistId, 0 as goals, count(*) as assist
        from Goal
        where AssistId is not null
        group by GameId, AssistId
    ) as q
    group by GameId, player
) as q2
inner join
Player as t
on (q2.player=t.PlayerId)
order by GameId, LastName

http://sqlfiddle.com/#!9/7b135a/5