MySql - 排名,给定玩家排名及

时间:2015-08-02 06:41:24

标签: mysql

我需要获得顶级球员,一名球员的排名以及少数排名靠前的球员。

为了更清楚地解释,下面的表是我想要的,它按分数显示前3名球员,给定球员的等级(id = 11)和2名得分刚好超过给定球员的球员:

+----+------+-------+--------+------+
| id | name | score | @rk:=0 | rank |
+----+------+-------+--------+------+
|  7 | g    |    31 |      0 |    1 |
|  8 | h    |    29 |      0 |    2 |
|  9 | i    |    28 |      0 |    3 |
|  4 | d    |    23 |      0 |    8 |
| 11 | k    |    21 |      0 |    9 |
|  1 | a    |    20 |      0 |   10 |
+----+------+-------+--------+------+

样本数据:

CREATE TABLE test (
id int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
name varchar(20),
score int
);

INSERT INTO test (name,score) VALUES ("a", 20),("b", 19),("c", 23),("d", 23),
("e", 27),("f", 25),("g", 31),("h", 29),("i", 28),("j", 24),("k", 21);

我已经设法显示排名,顶级球员,给定球员:

SELECT id,name,score,rank FROM
(SELECT *,@rk:=@rk+1 AS rank FROM test, (SELECT @rk:=0) r WHERE 1 ORDER BY score DESC) AS s
WHERE rank<=3 OR id=11 ORDER BY rank ASC

结果:

+----+------+-------+------+
| id | name | score | rank |
+----+------+-------+------+
|  7 | g    |    31 |    1 |
|  8 | h    |    29 |    2 |
|  9 | i    |    28 |    3 |
| 11 | k    |    21 |    9 |
+----+------+-------+------+

我很难展示那些在给定球员身上得分(高于或低于id = 4且id = 1)的球员。

我更喜欢1 sql查询,考虑到性能,因为数据可能很大。

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。为了找到得分球员,我首先尝试查询(中间部分 - s2和s3)给定球员的排名,存储在varian @givenrank中。 mysql查询如下:

SELECT id,name,rank FROM
(SELECT *,@rk:=@rk+1 AS rank FROM test, (SELECT @rk:=0) r WHERE 1 ORDER BY score DESC) AS s,

(SELECT @givenrank:=rank2 FROM
(SELECT *,@rk2:=@rk2+1 AS rank2 FROM test, (SELECT @rk2:=0) r2 ORDER BY score DESC) AS s2
WHERE id=11) AS s3

WHERE rank<=3 OR (@givenrank-1<=rank AND rank<=@givenrank+1) OR id=11 ORDER BY rank ASC;

结果正是我想要的:

+----+------+------+
| id | name | rank |
+----+------+------+
|  7 | g    |    1 |
|  8 | h    |    2 |
|  9 | i    |    3 |
|  4 | d    |    8 |
| 11 | k    |    9 |
|  1 | a    |   10 |
+----+------+------+

一些新问题:

  • 看起来查询必须处理相同的数据几次(s,s2,s3非常相似)。有没有想过优化/加速它们?
  • 如果数据具有给定用户的记录,则查询效果很好。如果不是,则不返回顶级玩家列表(如我所料),而是返回空结果(因为s3为空)。要检查它,只需将所有id = 11替换为id = 111。

为解决第二个问题,我将查询分为两个,如下所示。首先查询rank varian,如果为null,则不会影响结果。它适用于两种情况(给定的玩家在表中有或没有记录)。但是,使用两个查询不是我喜欢的解决方案(我更喜欢1个查询)。有什么想改进吗?

SELECT @givenrank:=rank2 FROM
(SELECT *,@rk2:=@rk2+1 AS rank2 FROM test, (SELECT @rk2:=0) r2 ORDER BY score DESC) AS s2
WHERE id=11;

SELECT  id,name,rank FROM
(SELECT *,@rk:=@rk+1 AS rank FROM test, (SELECT @rk:=0) r WHERE 1 ORDER BY score DESC) AS s
WHERE rank<=3 OR (@givenrank IS NOT NULL AND @givenrank-1<=rank AND rank<=@givenrank+1) OR id=11 ORDER BY rank ASC;