sma*_*esh 8 mysql hibernate tie rank
我有一个表Player的以下表结构
Table Player {
Long playerID;
Long points;
Long rank;
}
Run Code Online (Sandbox Code Playgroud)
假设玩家ID和积分具有有效值,我可以根据单个查询中的积分数更新所有玩家的等级吗?如果两个人拥有相同数量的积分,那么他们应该排名等级.
更新:
我正在使用hibernate使用建议作为本机查询的查询.Hibernate不喜欢使用变量,特别是':'.有谁知道任何变通方法?通过不使用变量或在这种情况下使用HQL解决hibernate的限制?
Dan*_*llo 16
一种选择是使用排名变量,例如:
UPDATE player
JOIN (SELECT p.playerID,
@curRank := @curRank + 1 AS rank
FROM player p
JOIN (SELECT @curRank := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Run Code Online (Sandbox Code Playgroud)
该JOIN (SELECT @curRank := 0)部分允许变量初始化而无需单独的SET命令.
进一步阅读这个主题:
测试用例:
CREATE TABLE player (
playerID int,
points int,
rank int
);
INSERT INTO player VALUES (1, 150, NULL);
INSERT INTO player VALUES (2, 100, NULL);
INSERT INTO player VALUES (3, 250, NULL);
INSERT INTO player VALUES (4, 200, NULL);
INSERT INTO player VALUES (5, 175, NULL);
UPDATE player
JOIN (SELECT p.playerID,
@curRank := @curRank + 1 AS rank
FROM player p
JOIN (SELECT @curRank := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Run Code Online (Sandbox Code Playgroud)
结果:
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 1 | 150 | 4 |
| 2 | 100 | 5 |
+----------+--------+------+
5 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
更新:刚刚注意到您需要联系以共享相同的排名.这有点棘手,但可以通过更多变量解决:
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + 1,
@curRank) AS rank,
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Run Code Online (Sandbox Code Playgroud)
对于测试用例,让我们添加另一个175分的玩家:
INSERT INTO player VALUES (6, 175, NULL);
Run Code Online (Sandbox Code Playgroud)
结果:
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 6 | 175 | 3 |
| 1 | 150 | 4 |
| 2 | 100 | 5 |
+----------+--------+------+
6 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
如果你要求排名跳过一个地方以防平局,你可以添加另一个IF条件:
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + 1,
@curRank) AS rank,
IF(@lastPoint = p.points,
@curRank := @curRank + 1,
@curRank),
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Run Code Online (Sandbox Code Playgroud)
结果:
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 6 | 175 | 3 |
| 1 | 150 | 5 |
| 2 | 100 | 6 |
+----------+--------+------+
6 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
注意:请考虑我建议的查询可以进一步简化.
小智 6
丹尼尔,你有非常好的解决方案.除了一点 - 领带案例.如果3个玩家之间发生平局,则此更新无效.我改变了你的解决方案如下:
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + @nextrank,
@curRank) AS rank,
IF(@lastPoint = p.points,
@nextrank := @nextrank + 1,
@nextrank := 1),
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0, @nextrank := 1) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5621 次 |
| 最近记录: |