Оператор обновления MySQL для сохранения позиций рейтинга - PullRequest
10 голосов
/ 07 июля 2010

Я пытаюсь разобраться в запросе и просто не могу понять. Буду признателен, если кто-нибудь даст мне указатель. В качестве простого примера того, чего я пытаюсь достичь, у меня есть эти записи в базе данных

Score|Ranking
-------------
100  |0
200  |0
300  |0

И я хотел бы, чтобы в поле «Рейтинг» содержалось 1,2,3, в зависимости от того, кто набрал наибольшее количество очков, поэтому результат должен быть:

Score|Ranking
-------------
100  |3
200  |2
300  |1

В данный момент я делаю цикл for next для всех этих записей, но, учитывая, что на самом деле это может быть несколько тысяч - это может занять вечность! У кого-нибудь есть идея магического запроса, которая бы сделала это за один раз?

Ответы [ 5 ]

18 голосов
/ 07 июля 2010

Вот способ сделать это:

SET @r=0;
UPDATE table SET Ranking= @r:= (@r+1) ORDER BY Score DESC;

/* use this if you just want to pull it from the db, but don't update anything */
SET @r=0;
SELECT *, @r:= (@r+1) as Ranking FROM table ORDER BY Score DESC;
5 голосов
/ 07 июля 2010

Это создает встроенный оператор обновления, который будет ранжировать ваших игроков, увеличиваясь по переменной @rc. Я использовал его много раз в очень похожих случаях, он хорошо работает и сохраняет все это на стороне БД.

SET @rc = 0;
UPDATE players JOIN (SELECT @rc := @rc + 1 AS rank, id FROM players ORDER BY rank DESC)
AS order USING(id) SET players.rank = order.rank;

id считается первичным ключом для вашей таблицы players.

5 голосов
/ 07 июля 2010

В MySQL вы можете использовать row_number .

Вот пример использования его в SELECT:

select @rownum:=@rownum+1 ‘rank’, p.* 
from player p, (SELECT @rownum:=0) r 
order by score desc;

Если вы INSERT INTO используете SELECT, как это, вы получите свой рейтинг.

2 голосов
/ 04 января 2013
SET @r = 0;
UPDATE players JOIN (SELECT @r := @r + 1 AS rank, id FROM players ORDER BY rank DESC)
AS sorted USING(id) SET players.rank = sorted.rank;
0 голосов
/ 07 ноября 2012

Я покажу вам, как это сделать [для интервальных функций обновления sql]

выберите:

set @currentRank = 0,
    @lastRating = null,
    @rowNumber = 1;
select
    *,
    @currentRank := if(@lastRating = `score`, @currentRank, @rowNumber) `rank`,
    @rowNumber := @rowNumber + if(@lastRating = `score`, 0, 1) `rowNumber`,
    @lastRating := `score`
from `table`
order by `score` desc

Обновление:

set @currentRank = 0,
    @lastRating = null,
    @rowNumber = 1;
update 
    `table` r
    inner join (
        select
            `primaryID`,
            @currentRank := if(@lastRating = `score`, @currentRank, @rowNumber) `rank`,
            @rowNumber := @rowNumber + if(@lastRating = `score`, 0, 1) `rowNumber`,
            @lastRating := `score`
        from `table`
        order by `score` desc
    ) var on
        var.`primaryID` = r.`primaryID`
set
    r.`rank` = var.`rank`

Я не делал никаких проверок производительности на этом, за исключением тестирования, что он работает

...