Description

Table: Players

Column NameType
player_idint
group_idint
  • player_id is the primary key (column with unique values) of this table.
  • Each row of this table indicates the group of each player.

Table: Matches

Column NameType
match_idint
first_playerint
second_playerint
first_scoreint
second_scoreint
  • match_id is the primary key (column with unique values) of this table.
  • Each row is a record of a match, first_player and second_player contain the player_id of each match.
  • first_score and second_score contain the number of points of the first_player and second_player respectively.
  • You may assume that, in each match, players belong to the same group.

Problem Statement

The winner in each group is the player who scored the maximum total points within the group. In the case of a tie, the lowest player_id wins.

Write a solution to find the winner in each group.

Return the result table in any order. The result format is in the following example.

Example 1:

Input:

  • Players table:
player_idgroup_id
151
251
301
451
102
352
502
203
403
  • Matches table:
match_idfirst_playersecond_playerfirst_scoresecond_score
1154530
2302512
3301520
4402052
5355011

Output:

group_idplayer_id
115
235
340

Solution

The problem looks difficult but it’s not so much. Essentially, we need score per player. This is union of first_player score and second_player score.

1WITH unioned_scores AS (
2    SELECT first_player AS player_id, first_score AS score
3    FROM Matches
4    UNION ALL
5    SELECT second_player AS player_id, second_score AS score
6    FROM Matches
7) SELECT * FROM unioned_scores;
player_idscore
153
301
302
405
351
450
252
150
202
501

Once you have the unioned_score, you can calculate score per player using GROUP BY clause.

1SELECT player_id, SUM(score) AS total_score
2FROM unioned_scores
3GROUP BY player_id
player_idtotal_score
153
303
405
351
450
252
202
501

Next, you need to rank players per group. This can be done using RANK(), DENSE_RANK() or ROW_NUMBER() functions. For this the window clause should be PARTITION BY group_id ORDER BY total_score DESC, player_id ASC.

 1WITH unioned_scores AS (
 2    SELECT first_player AS player_id, first_score AS score
 3    FROM Matches
 4    UNION ALL
 5    SELECT second_player AS player_id, second_score AS score
 6    FROM Matches
 7), scores_per_player AS (
 8    SELECT player_id, SUM(score) AS total_score
 9        FROM unioned_scores
10        GROUP BY player_id
11), ranked_players AS (
12    SELECT 
13        group_id, Players.player_id, 
14        DENSE_RANK() OVER (PARTITION BY group_id ORDER BY total_score DESC, player_id ASC) AS rnk
15        FROM scores_per_player
16        JOIN Players ON scores_per_player.player_id = Players.player_id
17) SELECT * FROM ranked_players order by rnk
group_idplayer_idrnk
1151
2351
3401
1302
2502
3202
1253
1454

The last thing is to filter only those rows with rnk = 1. This can be done using WHERE clause. This is what brings you the final result.

 1WITH unioned_scores AS (
 2    SELECT first_player AS player_id, first_score AS score
 3    FROM Matches
 4    UNION ALL
 5    SELECT second_player AS player_id, second_score AS score
 6    FROM Matches
 7), scores_per_player AS (
 8    SELECT player_id, SUM(score) AS total_score
 9        FROM unioned_scores
10        GROUP BY player_id
11), ranked_players AS (
12    SELECT 
13        group_id, Players.player_id, 
14        DENSE_RANK() OVER (PARTITION BY group_id ORDER BY total_score DESC, player_id ASC) AS rnk
15        FROM scores_per_player
16        JOIN Players ON scores_per_player.player_id = Players.player_id
17) SELECT group_id, player_id FROM ranked_players 
18    WHERE rnk = 1;