MySQL select 语句 - 如何计算当前排名
Posted
技术标签:
【中文标题】MySQL select 语句 - 如何计算当前排名【英文标题】:MySQL select statement - How to calculate the current ranking 【发布时间】:2014-12-10 06:24:16 【问题描述】:我有一个名为 user_rankings
的表,其中存储了每个用户的投票 (voted
)。我想显示当前用户的排名(本周),这取决于用户获得了多少票。
举例说明:
RANK-NR、用户名、已投票 1, name1, 18 次 2, name1, 16 次 (我的排名在这里),我的名字,13次在这个例子中,我的排名应该是 3。如果我有 17 票,我会是第 2 名。如果我上面有 5 个用户,我会是第 8 名。我想你明白了。
现在我可以在 php 中使用递增的$i
轻松显示排名数字。但是我只想显示一个限制为十个用户的列表(前十名列表),然后直接显示我当前的排名,如果我还没有进入前十名的话。所以我只是想知道如何使用 mysql 获得我的确切排名。
我假设这个列表中有数百个用户,他们的票数不同。
这是我此刻的声明:
SELECT
`voted`
FROM `users_ranking`
WHERE
`uid`='".$_SESSION['uid']."'
AND
WEEKOFYEAR(`date`)=WEEKOFYEAR(NOW())
LIMIT 1
【问题讨论】:
查看这个答案:***.com/a/14294565 Find the ranking of an integer in mysql的可能重复 【参考方案1】:我不能给你确切的代码,但我认为下面可以给你一些想法
从中选择“RANK-NR”、“USERNAME”、“VOTED”
(
选择 'RANK-NR', 'USERNAME', 'VOTED', rank() over (order by 'voted' desc) 作为排名
来自用户排名
在哪里
uid
='".$_SESSION['uid']."'
和
星期几(date
)=星期几(现在())
) 作为 abc
在哪里
排名
我认为 rank() over (order by) 应该可以工作
【讨论】:
【参考方案2】:我刚刚发现这个解决方案有效:
SELECT *
FROM
(
SELECT @ranking:= @ranking + 1 rank,
a.`uid`
FROM `users_ranking` a, (SELECT @ranking := 0) b
ORDER BY a.`votes` DESC
) s
WHERE `uid`='".$_SESSION['uid']."'
AND
WEEKOFYEAR(`date`)=WEEKOFYEAR(NOW())
LIMIT 1
【讨论】:
严格来说,我认为您应该按顺序(从子查询中)从 users_ranking 中获取记录,然后将排名添加到其中。这将强制 MySQL 在计算排名之前按顺序获得投票。 你能发一个例子吗? @Kickstart【参考方案3】:好的,以我的评论为例。您所拥有的通常会起作用,但没有什么可以强制 MySQL 在应用排名之前进行排序。
因此,使用额外级别的子查询会给你这个(未经测试)。内部子查询以正确的顺序获取相关周的所有用户 ID,而下一个外部子查询将排名应用于此有序结果集。外部查询只获取您需要的单个返回行。
SELECT c.rank, c.uid
FROM
(
SELECT @ranking:= @ranking + 1 rank, a.uid
FROM
(
SELECT uid, votes
FROM `users_ranking`
WHERE WEEKOFYEAR(`date`) = WEEKOFYEAR(NOW())
ORDER BY votes DESC
) a,
(SELECT @ranking := 0) b
) c
WHERE c.uid = '".$_SESSION['uid']."'
LIMIT 1
另一种避免子查询并避免需要变量的可能性是进行连接。这是(错误)使用 HAVING 将结果缩小到您感兴趣的单行。此解决方案的缺点是,如果多个用户具有相同的分数,他们将各自获得相同的排名。
SELECT b.uid, COUNT(a.uid)
FROM users_ranking a
LEFT OUTER JOIN users_ranking b
ON WEEKOFYEAR(a.`date`) = WEEKOFYEAR(b.`date`)
AND a.votes >= b.votes
GROUP BY b.uid
HAVING b.uid = '".$_SESSION['uid']."'
编辑
给出前10名的排名:-
SELECT b.uid, COUNT(a.uid) AS rank
FROM users_ranking a
LEFT OUTER JOIN users_ranking b
ON WEEKOFYEAR(a.`date`) = WEEKOFYEAR(b.`date`)
AND a.votes >= b.votes
GROUP BY b.uid
ORDER BY rank
LIMIT 10
虽然在这种情况下使用子查询可能会更快。然后,您可以将 LIMIT 子句与 ORDER BY 一起放在子查询中,因此只需使用变量将排名添加到 10 行。
我不确定如何将其与单个用户的查询结合起来,主要是因为我不确定您想如何将两个结果合并在一起。
【讨论】:
感谢您的详细回复。但是,在我在这里将解决方案标记为正确之前,您能否再解释一下您的解决方案?这是关于性能问题吗?我的 MySQL 语句到底发生了什么不同?此外,不能有两个用户的投票数相同,因为我正在验证这在我的系统中是不允许的。 第一个解决方案在添加排名之前强制排序。这是对您自己的解决方案的简单升级。这个解决方案(和你的)的缺点是它使用子查询,这些往往会导致性能不佳(因为 MySQL 通常不会从子查询中携带索引),而且它会强制内部查询带回应用了排名的所有记录。我的第二个解决方案避免了子查询并且应该使用索引(使用 INNER JOIN 而不是 LEFT OUTER JOIN 可能更有效)。 我对子查询不熟悉,所以直到现在我才知道性能不佳。我现在在很多网站上都读到了。所以我想使用加入解决方案。但是存在您的第二个解决方案分配给特定用户的问题。在该 select 语句之上,我有所有用户的 Top10 列表。所以有两个查询。是否可以以某种方式将它们缩短为一个查询以获得 top10 列表以及这个特定的登录用户?这是我的代码:pastebin.com/xY00gG4g 为此添加了建议,但不确定是否将 2 个查询合并在一起。以上是关于MySQL select 语句 - 如何计算当前排名的主要内容,如果未能解决你的问题,请参考以下文章