【问题标题】:How to get an entry's position from a complex query using MySQL?如何使用 MySQL 从复杂查询中获取条目的位置?
【发布时间】:2019-06-26 18:13:17
【问题描述】:

我想知道玩家在排行榜上的位置(排名)。我没有排行榜表,它是从users 表和查询生成的。这就是我获取条目的方式:

SELECT
   u.id as userId,
   u.xp as xp,
   u.nickname as nickname,
   SUM(opr.games_won) as wonGames,
   SUM(opr.games_lost) as lostGames 
FROM
   users u 
   INNER JOIN
      opponent_player_result opr ON u.id = opr.user_id 
WHERE
   u.last_login >= 1548374400000 
   AND u.xp > 0 
   AND u.zone_id = 1 
GROUP BY
   u.id 
ORDER BY
   u.xp DESC,
   wonGames DESC,
   lostGames ASC
LIMIT 0, 50;

xp 列用于存储玩家的经验值。在每场比赛后更新此栏。

opponent_player_result 是一个单独的表格,用于保存玩家的游戏结果:

+----+------------+-----------+-----------------+---------+
| id | games_lost | games_won | opponent_player | user_id |
+----+------------+-----------+-----------------+---------+
|  1 |          3 |         0 |               0 |       1 |
|  2 |          2 |         1 |               1 |       1 |
|  3 |          0 |         3 |               2 |       1 |
|  4 |          4 |         2 |               0 |       2 |
|  5 |          0 |         1 |               1 |       2 |
|  6 |          1 |         1 |               2 |       2 |
|  7 |          2 |         3 |               0 |       3 |
|  8 |          3 |         0 |               1 |       3 |
|  9 |          3 |         4 |               2 |       3 |
+----+------------+-----------+-----------------+---------+

您可能已经注意到,每个玩家都有 3 个对手玩家结果(因为玩家只能玩 3 个机器人)。

上面的查询会给我以下结果:

+--------+----+----------+----------+-----------+
| userId | xp | nickname | wonGames | lostGames |
+--------+----+----------+----------+-----------+
|      1 | 34 | nick1    |        4 |         5 |
|      3 | 29 | nick3    |        7 |         8 |
|      2 | 29 | nick2    |        4 |         5 |
+--------+----+----------+----------+-----------+

我没有使用 MySQL RANK() 函数,也没有增加变量来关联玩家的位置(也许这就是我应该做的)。

如何从上面的排行榜结果中获取单个玩家的位置?

例如,#id 3 的用户的排名为 2

这是我正在处理的用于在排行榜中查找玩家位置的查询:

SELECT u.id AS userId,
       u.xp AS xp,
       1 +
  (SELECT COUNT(*)
   FROM
     (SELECT SUM(opr.games_won) AS wonGames,
             SUM(opr.games_lost) AS lostGames
      FROM users AS p
      INNER JOIN opponent_player_result AS opr ON p.id = opr.user_id
      WHERE p.last_login >= 1548374400000
        AND p.xp > 0
        AND p.xp > u.xp
        AND p.zone_id = 1
      GROUP BY p.id
      ORDER BY p.xp DESC, wonGames DESC, lostGames ASC) AS counter) AS ranking
FROM users AS u
WHERE u.id = 1;

但我收到以下错误:

错误 1054 (42S22):“where 子句”中的未知列“u.xp”

据我所知,MySQL 只允许 1 级深度嵌套或子查询,但在我的示例中,我是 3 级深度。但是如何从子查询引用到外部查询呢?

这是获得排行榜的正确方法吗?我应该创建一个单独的表并定期更新它吗?我非常害怕性能受到影响。

我使用的是 MySQL 8.0 版本。

【问题讨论】:

  • 您使用的是哪个版本的 MySQL? RANK() 在 8.0 中可用。
  • @GMB 我使用的是 MySQL 8.0 版本。
  • “也许这就是我应该做的”:是的,你应该使用RANK()。我建议您尝试一下,如果您仍有问题,请回来。

标签: mysql sql rank


【解决方案1】:

这很简单,使用 MySQL 8.0 的排名函数。例如,DENSE_RANK 计算分区内每一行的排名(并列的记录被分配相同的排名)。

SELECT
   u.id as userId,
   u.xp as xp,
   u.nickname as nickname,
   SUM(opr.games_won) as wonGames,
   SUM(opr.games_lost) as lostGames,
   DENSE_RANK() OVER(ORDER BY u.xp DESC) rnk
FROM
   users u 
   INNER JOIN
      opponent_player_result opr ON u.id = opr.user_id 
WHERE
   u.last_login >= 1548374400000 
   AND u.xp > 0 
   AND u.zone_id = 1 
GROUP BY
   u.id, u.xp, u.nickname
ORDER BY
   u.xp DESC,
   wonGames DESC,
   lostGames ASC
LIMIT 0, 50;

Demo on DB Fiddle

| userId | xp  | nickname | wonGames | lostGames | rnk |
| ------ | --- | -------- | -------- | --------- | --- |
| 1      | 34  | nick1    | 4        | 5         | 1   |
| 3      | 29  | nick3    | 7        | 8         | 2   |
| 2      | 29  | nick2    | 4        | 5         | 2   |

【讨论】:

  • @GMB 可以列出整张桌子,但是如何只为单个玩家获取?
  • @ZbarceaChristian :一种解决方案是将上述查询包装为:SELECT x.* FROM (<above query>) x WHERE x.userId = ?
  • @BarbarosÖzhan:非常感谢你的朋友!非常感谢您的评论。
  • @GMB - 我已经把它包装好了,它似乎正在工作。谢谢!我所做的是我删除了INNER JOIN 并将won_gameslost_games 放在users 表中。我更改了查询DENSE_RANK() OVER(ORDER BY u.xp DESC, u.won_gamesc DESC, u.lost_games ASC) rnk。我应该从主查询中删除ORDER BY u.xp, wonGames DESC, lostGames ASC 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
  • 2018-04-26
相关资源
最近更新 更多