寻找比赛中每个玩家组的冠军-PostgreSQL

问题描述 投票:2回答:1

PostgreSQL上的这个问题现在困扰着我很长时间。我尝试了一下,搜寻了所有可能但无法结束的结果,该结果将第3组的玩家考虑在内。因此,即使这个问题可能是重复的,也找不到正确的答案。希望有帮助。

问题如下:编写一个SQL查询,该查询返回一个包含每个组中获胜者的表。每条记录均应包含该组的ID和该组中获胜者的ID(来自同一组的玩家竞争)。记录应通过增加组的ID号来排序,如果出现平局,则ID最低的玩家获胜。

给出此模式:

玩家:

+-------------+-------+
| Column Name | Type  |
+-------------+-------+
| player_id   | int   |
| group_id    | int   |
+-------------+-------+

匹配项:

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| match_id      | int     |
| first_player  | int     |
| second_player | int     | 
| first_score   | int     |
| second_score  | int     |
+---------------+---------+

对于以下示例:

玩家表:

+-----------+------------+
| player_id | group_id   |
+-----------+------------+
| 20        | 2          |
| 30        | 1          |
| 40        | 3          |
| 45        | 1          |
| 50        | 2          |
| 40        | 1          |
+-----------+------------+

比赛表:

+------------+--------------+---------------+-------------+--------------+
| match_id   | first_player | second_player | first_score | second_score |
+------------+--------------+---------------+-------------+--------------+
| 1          | 30           | 45            | 10          | 12           |
| 2          | 20           | 50            | 5           | 5            |
| 3          | 65           | 45            | 10          | 10           |
| 4          | 30           | 65            | 3           | 15           |
| 5          | 45           | 65            | 8           | 4            |
+------------+--------------+---------------+-------------+--------------+

您的查询应返回:

+-----------+------------+------------+
| group_id  | winner_id  | tot_score  |
+-----------+------------+------------+ 
| 1         | 45         | 30         |
| 2         | 20         | 5          |
| 3         | 40         | 0          |
+-----------+------------+------------+

第1组中,玩家45分得分最高。在第2组中,两个玩家均获得5分,但玩家20的ID较低,因此他是获胜者。在小组3中,只有一名球员,尽管他没有参加任何比赛,但他是获胜者。

到目前为止,设法做到的最好的方法是(在PostgreSQL上:

SELECT group_id, player_id, score
FROM
(
    SELECT sq2.player_id, p.group_id, sq2.score, 
    RANK() OVER (PARTITION BY p.group_id ORDER BY score DESC) as position
    FROM
    (
      SELECT player_id, SUM(score) score
      FROM (
        SELECT first_player as player_id, first_score as score FROM matches
        UNION ALL
        SELECT second_player as player_id, second_score as score FROM matches
      ) as sq1
      GROUP BY player_id
    ) as sq2
    right join players p
    on p.player_id = sq2.player_id
) as sq3
WHERE position = 1 order by group_id, player_id

输出哪个:

+-----------+-----------------------+------------+
| group_id  | player_id             | score      |
+-----------+-----------------------+------------+ 
| 1         | 45                    | 30         |
| 2         | 20                    | 5          |
| 2         | 50                    | 5          |
| 3         | [NULL](instead of 40) | [NULL] (should be 0)|
+-----------+-----------------------+------------+

您能否帮助生成具有完整正确结果的查询? (以及第3组玩家的详细信息)

还想知道为什么查询会在player_id中为正确的连接返回NULL。感谢帮助!

*这个问题显然也是Leetcode.com上的一个问题,称为“锦标赛冠军” *

sql postgresql select subquery postgresql-9.5
1个回答
1
投票

您可以如下使用distinct on和聚合:

select distinct on (p.group_id)
    p.group_id,
    player_id winner_id, 
    coalesce(sum(first_score) filter(where p.player_id = m.first_player), 0)
        + coalesce(sum(second_score) filter(where p.player_id = m.second_player), 0) 
        tot_score
from players p
left join matches m on p.player_id in (m.first_player, m.second_player)
group by p.group_id, p.player_id
order by p.group_id, tot_score desc, p.player_id

Demo on DB Fiddle

group_id | winner_id | tot_score-------:| --------:| --------:1 | 45 | 302 | 20 | 53 | 40 | 0
© www.soinside.com 2019 - 2024. All rights reserved.