У меня такой запрос,
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
query. Таким образом, результат может быть таким. Чтобы пользователь мог просматривать свои ряды, когда они вошли в свою учетную запись.
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
Если вы не настаиваете на использовании 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
.
Рейтинг здесь относительно распределения баллов среди всех пользователей. Я считаю, что вы должны попробовать что-то, первоначально предложенное в этом ответе:
SELECT users.*,
@rownum := @rownum + 1 as rank
FROM users
CROSS JOIN (select @rownum := 0) r
ORDER BY score DESC
То, что он делает, это в основном упорядочить всех пользователей по количеству баллов и назначить каждому из них инкрементное значение "rank". Таким образом, лучший бомбардир будет иметь ранг 1, второй бомбардир будет иметь ранг 2 и т.д.
Имейте в виду, что это решение не "справедливо" - каждый пользователь будет иметь разный ранг, даже если все пользователи имеют одинаковый рейтинг. Если вы пытаетесь ранжировать пользователей так же, как в спорте (если у двух топ-соперников одинаковый балл, они оба занимают 1-е место, а следующий лучший конкурент занимает 3-е место, а не второе), вы должны подумать о другом решении.
where id=3
В вашем запросе вы можете добавить счетчик, например:
set @n:=0;
SELECT @i := @i + 1 AS rank, * FROM users ORDER BY score