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