一、题目来源
二、数据表结构
表:
TeamPoints
+-------------+---------+ | Column Name | Type | +-------------+---------+ | team_id | int | | name | varchar | | points | int | +-------------+---------+ team_id 包含唯一值。 这张表的每一行均包含了一支国家队的 ID,它所代表的国家,以及它在全球排名中的得分。没有两支队伍代表同一个国家。表:
PointsChange
+---------------+------+ | Column Name | Type | +---------------+------+ | team_id | int | | points_change | int | +---------------+------+ team_id 包含唯一值。 这张表的每一行均包含了一支国家队的 ID 以及它在世界排名中的得分的变化。 分数的变化分以下情况: - 0:代表分数没有改变 - 正数:代表分数增加 - 负数:代表分数降低 TeamPoints 表中出现的每一个 team_id 均会在这张表中出现。
三、需求
国家队的全球排名是按 降序排列 所有队伍的得分后所得出的排名。如果两支队伍得分相同,我们将按其名称的 字典顺序 排列以打破平衡。
每支国家队的分数应根据其相应的 points_change
进行更新。
编写解决方案来计算在分数更新后,每个队伍的全球排名的变化。
以 任意顺序 返回结果。
四、示例数据
输入: TeamPoints 表: +---------+-------------+--------+ | team_id | name | points | +---------+-------------+--------+ | 3 | Algeria | 1431 | | 1 | Senegal | 2132 | | 2 | New Zealand | 1402 | | 4 | Croatia | 1817 | +---------+-------------+--------+ PointsChange 表: +---------+---------------+ | team_id | points_change | +---------+---------------+ | 3 | 399 | | 2 | 0 | | 4 | 13 | | 1 | -22 | +---------+---------------+ 输出: +---------+-------------+-----------+ | team_id | name | rank_diff | +---------+-------------+-----------+ | 1 | Senegal | 0 | | 4 | Croatia | -1 | | 3 | Algeria | 1 | | 2 | New Zealand | 0 | +---------+-------------+-----------+ 解释: 世界排名如下所示: +---------+-------------+--------+------+ | team_id | name | points | rank | +---------+-------------+--------+------+ | 1 | Senegal | 2132 | 1 | | 4 | Croatia | 1817 | 2 | | 3 | Algeria | 1431 | 3 | | 2 | New Zealand | 1402 | 4 | +---------+-------------+--------+------+ 在更新分数后,世界排名变为下表: +---------+-------------+--------+------+ | team_id | name | points | rank | +---------+-------------+--------+------+ | 1 | Senegal | 2110 | 1 | | 3 | Algeria | 1830 | 2 | | 4 | Croatia | 1830 | 3 | | 2 | New Zealand | 1402 | 4 | +---------+-------------+--------+------+ 由于在更新分数后,Algeria 和 Croatia 的得分相同,因此根据字典顺序对它们进行排序。 Senegal 丢失了22分但他们的排名没有改变。 Croatia 获得了13分但是他们的排名下降了1名。 Algeria 获得399分,排名上升了1名。 New Zealand 没有获得或丢失分数,他们的排名也没有发生变化。
五、分析
1.文字分析
本题需求为获取世界排名的变化,
第一步:根据需求,首先求出没有变化前的国家队伍得分排名,对分数进行降序,对队伍名称升序排列获得本来的排名old_rk;
第二步:求出国家队伍得分变化后得分排名,根据points + point_change 计算变化后的得分并进行降序排列,队伍名称升序排列获取新的排名new_rk;
第三步:最终使用前两步结果中的new_rk和old_rk进行相减计算,需要注意得到的排名为unsigned无符号数,无法得到负值,因此在相减之前需要对他们进行cast类型转换,把它们转换成signed有符号数再进行相减。
2.图解
六、代码实现
WITH t1 AS (
SELECT
tp.team_id,
name,
ROW_NUMBER() OVER(ORDER BY points DESC, name) AS old_rk,
ROW_NUMBER() OVER(ORDER BY points + points_change DESC, name) AS new_rk
FROM TeamPoints AS tp
LEFT JOIN PointsChange AS pc on tp.team_id = pc.team_id
)
SELECT
team_id,
name,
CAST(old_rk AS SIGNED) - CAST(new_rk AS SIGNED) AS rank_diff
FROM t1;
七、总结
本题获取世界排名变化,只需要根据变化前后的分数以及名称进行排序求出排名然后将前后的排名值进行相减即可求出;
但是本题存在一个小坑,就是排名函数得到的排名值,一般为bigint unsigned 即无符号数 的 bigint类型,无符号数相减无法得到负值,如果结果有负值运行结果就会保存,所以在相减之前我们需要把无符号数先转换为signed 有符号数,使用cast函数进行转换,转换之后再相减就可以得到负值了。
cast() 函数用于将一个值或表达式转换为指定的数据类型。它的基本语法是:
CAST(expression AS target_type)
,其中 expression
是要转换的值或表达式,target_type
是目标数据类型,比如CHAR
、DATE
、TIME
、DATETIME
、SIGNED
(有符号整数)、UNSIGNED
(无符号整数)等。