如何使用集合中的查找功能基于分数进行用户排名?

时间:2018-08-08 09:16:35

标签: php mysql

我有这样的查询

SELECT * FROM users ORDER BY score

所以,结果是这样的。

Array
(
    [0] => stdClass Object
        (
            [userid] => 3
            [user] => John Doe
            [score] => 50
        )

    [1] => stdClass Object
        (
            [userid] => 1
            [user] => Mae Smith
            [score] => 38
        )

    [2] => stdClass Object
        (
            [userid] => 2
            [user] => Mark Sam
            [score] => 26
        )
)

但是,我想使用find_in_set查询来添加排名。因此结果可能是这样的。这样,用户登录帐户后就可以查看其排名。

Array
(
    [0] => stdClass Object
        (
            [userid] => 3
            [user] => John Doe
            [score] => 50
            [rank] => 1
        )

    [1] => stdClass Object
        (
            [userid] => 1
            [user] => Mae Smith
            [score] => 38
            [rank] => 2
        )

    [2] => stdClass Object
        (
            [userid] => 2
            [user] => Mark Sam
            [score] => 26
            [rank] => 3
        )
)

我尝试过这个。

$listOfUser = array();
foreach($users as $user) {
   $listOfUser[] = $user->userid;
}

并使用了另一个查询

$userid = 2 // => id of loggedin user
SELECT *, find_in_set($userid, $listOfUser) as rank FROM users where userid=$userid ORDER BY score

所以,我得到了这个结果

Array
(

    [1] => stdClass Object
        (
            [userid] => 2
            [user] => Mark Sam
            [score] => 26
            [rank] => 3
        )
)

这是正确的。但是,还有另一种方法可以只使用一个SQL查询而不使用foreach循环来查询结果?

这样的事情。

$userid = 2 // => id of loggedin user
SELECT *, find_in_set($userid, (SELECT * FROM users ORDER BY score)) as rank FROM users where userid=$userid ORDER BY score

但是我遇到了这个错误Subquery returns more than 1 row

3 个答案:

答案 0 :(得分:4)

如果您不坚持使用find_in_set,则可以通过简单的连接获得结果。您要求提供用户列表(p),对于您要求的每个用户,有多少用户的得分比他或她更好(c):

SELECT p.userid, COUNT(c.userid) AS rank
FROM users AS p
LEFT JOIN users AS c ON c.score > p.score
GROUP BY p.userid

即使您添加了其他条件(例如WHERE p.userid = 123),此方法也有效。 如果更多用户具有相同分数,则排名将类似于0,1,2,2,2,5,6

答案 1 :(得分:0)

在查询中,您可以添加计数器,如下所示:

set @n:=0; 
SELECT @i := @i + 1 AS rank, * FROM users ORDER BY score

答案 2 :(得分:0)

此处的排名与所有用户的分数分布有关。我相信您应该尝试最初建议的in this answer

SELECT users.*, 
   @rownum := @rownum + 1 as rank
FROM users
CROSS JOIN (select @rownum := 0) r
ORDER BY score DESC

它的作用基本上是按分数对所有用户进行排序,并为每个用户分配一个增量值“等级”。因此,最高得分手的排名为1,第二得分手的排名为2,依此类推。

请记住,此解决方案不是“公平” -即使所有用户的得分都相同,每个用户的排名也会不同。强>。如果您尝试像在体育运动中那样对用户进行排名(如果两个顶级竞争对手的得分相同,则他们都排在第一位,次优的竞争对手则排在第三位,而不是第二位),您应该考虑采用不同的解决方案。