Расчет ранга в PHP / MySQL - PullRequest
       4

Расчет ранга в PHP / MySQL

1 голос
/ 30 января 2011

У меня есть таблица в MySQL, скажем, например, есть два поля: Имя пользователя, GameName и Score.Я хочу рассчитать рейтинг пользователя для индивидуального игрового имени, чтобы я мог выполнить запрос

SELECT * FROM scores WHERE `GameName` = 'Snake' ORDER BY `Score` DESC

, чтобы получить список всех пользователей в порядке убывания и назначить число каждому пользователю.

Но есть ли более простой способ получить звание для индивидуального пользователя, чем выделение всей таблицы, поскольку это не кажется слишком эффективным.

Спасибо

Ответы [ 7 ]

4 голосов
/ 31 января 2011

Если вы хотите получить общий рейтинг, вам, к сожалению, придется отсортировать всю таблицу. Проще говоря, вы не можете знать чей-то ранг в таблице, не зная других рангов в таблице.

Тем не менее, если вы беспокоитесь о производительности, здесь есть довольно простое решение - кэшировать результат вашего запроса ранжирования (может быть, в другую таблицу MySQL!) И запрашивать его для всех ваших чтений. Когда кто-то публикует новый счет, пересчитайте свою временную таблицу. Вы можете периодически сбрасывать все записи под определенным рангом (скажем, любой, кто занимает рейтинг ниже 100, удаляется из таблицы результатов), чтобы поддерживать быстрые повторные вычисления, поскольку никто никогда не поднимется в рейтинге после сбивания с более высоким результатом.

# Create your overall leaderboards once
create table leaderboards (rank integer primary key, score_id integer, game varchar(65), user_id integer, index game_user_id_idx (game, user_id))


# To refresh your leaderboard, we'll query the ranks for the game into a temporary table, flush old records from scores, then copy
# the new ranked table into your leaderboards table.
# We'll use MySQL's CREATE TABLE...SELECT syntax to select our resultset into it directly upon creation.
create temporary table tmp_leaderboard (rank integer primary key auto_increment, score_id integer, game varchar(65), user_id integer)
  select ID, GameName, UserID, from scores where GameName = '$game' order by score desc;

# Remove old rankings from the overall leaderboards, then copy the results of the temp table into it.
delete from leaderboards where game = '$game';
insert into leaderboards (rank, score_id, game, user_id)
  select rank, score_id, game, user_id from tmp_leaderboard;

# And then clean up the lower scores from the Scores table
delete from scores join tmp_leaderboard on scores.id = tmp_leaderboard.score_id, scores.GameName = tmp_leaderboard.game where tmp_leaderboard.rank < 100;

# And we're done with our temp table
drop table tmp_leaderboard;

Затем, всякий раз, когда вы хотите прочитать рейтинг игры:

select rank from leaderboards where game = '$game' and user_id = '$user_id';
1 голос
/ 12 июля 2012

Мое решение для одного запроса:

select @rank:=@rank+1 AS Rank,L1.* from 
    (select @rank:=0) as L2,
    (select i.*,count(*) as sum 
        FROM 
        transactions t
        LEFT JOIN companies c on (c.id = t.company_id)  
        LEFT JOIN company_industries ci on (c.id = ci.company_id)  
        LEFT JOIN industries i on (ci.industry_id = i.id)
        GROUP by i.name 
        ORDER BY sum desc ) as L1;
1 голос
/ 31 января 2011

Вы не можете избежать чтения большого количества данных в таблице - но вам не нужно перетаскивать их обратно в сценарий обработки:

SELECT COUNT(*)
FROM scores 
WHERE `GameName` = 'Snake'
AND user=$some_user;

(так как вывероятно, вы хотите, чтобы первый человек имел ранг «1», а не «0», увеличьте результат).

Однако если вам нужно часто выполнять запрос, стоит сохранить материализованное представление отсортированных результатов.

1 голос
/ 31 января 2011

Интересно посмотреть, есть ли способ получить ранг в MySQL, но вот как вы могли бы сделать это в PHP:

function getRank($user, $game, $limit=50) {
    $sql = "
SELECT @rank:=@rank+1 AS Rank, User, GameName
FROM scores, (SELECT @rank:=1) AS i
WHERE `GameName` = '$game' 
ORDER BY `Score` DESC
LIMIT 0, $limit
";

    $result =  mysql_query($sql);

    while ($row = mysql_fetch_assoc($result)) {
        if ($row['User'] == $user) {
            return $row['Rank'];
        }
    }

    return -1;
}

Обратите внимание, я поставил ограничение там, потому что иначене получит, но 30 результатов назад.И он возвращает -1, если игрок не получил рейтинг.

1 голос
/ 30 января 2011

SELECT * FROM scores WHERE 'GameName' = 'Snake' && userID = '$userID' ORDER BY 'Score' DESC

1 голос
/ 30 января 2011

получить идентификатор пользователя из таблицы пользователей и использовать его в запросе


SELECT * FROM scores WHERE `GameName` = 'Snake' 
and `youruseridfield` = '$useridvalue'
ORDER BY `Score` DESC
0 голосов
/ 30 января 2011

Вы должны добавить индексы к GameName и Score.(И не забудьте выйти из GameName перед вставкой в ​​запрос => mysql_real_escape_string).@ Брайан: не должно ли быть "И", чем "&&"?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...