Как использовать поиск в наборе для рейтинга пользователей на основе оценки?

0

У меня такой запрос,

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

  • 1
    Вы рассматривали возможность использования соединения? Или мне чего-то не хватает?
  • 0
    нет, я не знаю, как использовать объединение с помощью find_in_set
Показать ещё 2 комментария
Теги:

3 ответа

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.

  • 0
    Смотрите пример скрипта : sqlfiddle.com/#!9/ada990/5
  • 0
    Это работает, да! Но я хочу, чтобы ранг начинался с единицы, а не с нуля. Как я могу это сделать?
Показать ещё 2 комментария
0

Рейтинг здесь относительно распределения баллов среди всех пользователей. Я считаю, что вы должны попробовать что-то, первоначально предложенное в этом ответе:

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

То, что он делает, это в основном упорядочить всех пользователей по количеству баллов и назначить каждому из них инкрементное значение "rank". Таким образом, лучший бомбардир будет иметь ранг 1, второй бомбардир будет иметь ранг 2 и т.д.

Имейте в виду, что это решение не "справедливо" - каждый пользователь будет иметь разный ранг, даже если все пользователи имеют одинаковый рейтинг. Если вы пытаетесь ранжировать пользователей так же, как в спорте (если у двух топ-соперников одинаковый балл, они оба занимают 1-е место, а следующий лучший конкурент занимает 3-е место, а не второе), вы должны подумать о другом решении.

  • 0
    Но если я выбираю конкретного пользователя, ранг всегда равен 1, когда я добавляю образец: where id=3
  • 0
    Вы можете обернуть вышеупомянутый запрос в SELECT * FROM (над подзапросом) tmp WHERE tmp.id = 3 - и вы получите свой результат.
0

В вашем запросе вы можете добавить счетчик, например:

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню