Вот альтернативное решение: вообще не хранить ранги!: -)
Вы можете рассчитать их на лету.
Пример:
SELECT id, (@next_rank := IF(@score <> score, 1, 0)) nr,
(@score := score) score, (@r := IF(@next_rank = 1, @r + 1, @r)) rank
FROM rank, (SELECT @r := 0) dummy1
ORDER BY score DESC;
Результат:
+------+----+-------+------+
| id | nr | score | rank |
+------+----+-------+------+
| 2 | 1 | 23 | 1 |
| 4 | 1 | 17 | 2 |
| 1 | 0 | 17 | 2 |
| 5 | 1 | 10 | 3 |
| 3 | 1 | 2 | 4 |
+------+----+-------+------+
nr
здесьaт вспомогательный столбец, который указывает, следует ли нам назначать следующий ранг или нет.
Вы можете заключить этот запрос в другой select
и выполнить разбиение по страницам, например.
SELECT id, score, rank
FROM (SELECT id, (@next_rank := IF(@score <> score, 1, 0)) nr,
(@score := score) score, (@r := IF(@next_rank = 1, @r + 1, @r)) rank
FROM rank, (SELECT @r := 0) dummy1
ORDER BY score DESC) t
WHERE rank > 1 and rank < 3;
Результат:
+------+-------+------+
| id | score | rank |
+------+-------+------+
| 4 | 17 | 2 |
| 1 | 17 | 2 |
+------+-------+------+
ПРЕДОСТЕРЕЖЕНИЕ : поскольку теперь rank
является вычисляемым столбцом, вы не можете индексировать его и эффективно перемещаться далеко в набор данных (то есть «выбирать записи с рангами от 3000 до 3010»«).Но это все еще хорошо для «выбора первых N рангов» (при условии, что вы поставили соответствующий LIMIT
в запросе)