DaiBu DaiBu - 7 months ago 24
SQL Question

How do I SELECT a SUM of multiple GROUP BY rows?

I have a relationship table of players to matches and the points they've scored in each. I'm trying to do a SELECT in which I get a distinct list of players with their total points scored as well as the total points scored by all teams that they've been on. Since everything is in terms of single players, I don't know how to get out of the GROUP BY scope for only that single column. For the examples below, I'll just say that each team only has two players. In the actual database, each team has five if it matters. Thanks guys.

Table "matches":

match_id | winning_team |

56427859 | 0 |
56427860 | 1 |
56427861 | 1 |
56427862 | 0 |
56427863 | 1 |

etc...


Table "match_players":

match_id | team | player_id | points |

56427859 | 0 | 10 | 3 |
56427859 | 0 | 33 | 1 |
56427859 | 1 | 26 | 0 |
56427859 | 1 | 39 | 2 |
56427860 | 0 | 23 | 1 |
56427860 | 0 | 33 | 3 |
56427860 | 1 | 18 | 1 |
56427860 | 1 | 10 | 4 |

etc...


Desired result:

player_id | match_count | total_points | team_total_points | <- This should be
the total of all
10 | 2 | 7 | 9 | points scored by
18 | 1 | 1 | 5 | the player and
23 | 1 | 1 | 4 | his teammates
26 | 1 | 0 | 2 | in all matches.
33 | 2 | 4 | 8 |
39 | 1 | 2 | 2 |


The query:

SELECT
p.player_id,
COUNT(*) AS match_count,
SUM(CASE WHEN mp.team = m.winning_team THEN 1 ELSE 0 END) AS win_count,
SUM(points) AS total_points,
[________________________________________] AS team_total_points
FROM matches m
INNER JOIN match_players mp ON m.match_id = mp.match_id
INNER JOIN players p ON mp.player_id = p.player_id
GROUP BY player_id
ORDER BY player_id


Edit:

The "team" column simply defines red or blue, home or away, etc. Players can be on different teams in different matches. And players can swap teams between matches, like recess dodgeball.

Answer

The following query will calculate the total points for all players on the same team as each player.

SELECT p1.player_id, SUM(p2.total_points) AS team_total_points
FROM match_players AS p1
JOIN (SELECT match_id, team, SUM(points) as total_points
      FROM match_players
      GROUP BY match_id, team) AS p2
ON p1.match_id = p2.match_id AND p1.team = p2.team
GROUP BY p1.player_id

You can then join that with the original query to add the team totals.

SELECT
    p.player_id,
    COUNT(*) AS match_count,
    SUM(CASE WHEN mp.team = m.winning_team THEN 1 ELSE 0 END) AS win_count,
    SUM(points) AS total_points,
    mp2.team_total_points
FROM matches m
INNER JOIN match_players mp ON m.match_id = mp.match_id
INNER JOIN players p ON mp.player_id = p.player_id
INNER JOIN 
    (SELECT p1.player_id, SUM(p2.total_points) AS team_total_points
     FROM match_players AS p1
     JOIN (SELECT match_id, team, SUM(points) as total_points
           FROM match_players
           GROUP BY match_id, team) AS p2
     ON p1.match_id = p2.match_id AND p1.team = p2.team
     GROUP BY p1.player_id) AS mp2 ON mp2.player_id = p.player_id
GROUP BY player_id
ORDER BY player_id

DEMO