Обновите разряд в MySQL Table

У меня есть структура следующей таблицы для таблицы Player

Table Player {  
Long playerID;  
Long points;  
Long rank;  
}

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

ОБНОВЛЕНИЕ:

Я использую, в спящем режиме с помощью запроса, предложенного в качестве собственного запроса. Будьте в спящем режиме не любит использовать переменные, особенно ':'. Кто-либо знает о каких-либо обходных решениях? Или не используя переменные или работая вокруг ограничения hibernate в этом случае при помощи HQL?

8
задан smahesh 28 April 2010 в 21:05
поделиться

3 ответа

Один из вариантов - использовать ранжирующую переменную, например следующую:

UPDATE   player
JOIN     (SELECT    p.playerID,
                    @curRank := @curRank + 1 AS rank
          FROM      player p
          JOIN      (SELECT @curRank := 0) r
          ORDER BY  p.points DESC
         ) ranks ON (ranks.playerID = player.playerID)
SET      player.rank = ranks.rank;

JOIN (SELECT @curRank: = 0) позволяет инициализировать переменную, не требуя отдельной команды SET .

Дополнительная литература по этой теме:


Контрольный пример:

CREATE TABLE player (
   playerID int,
   points int,
   rank int
);

INSERT INTO player VALUES (1, 150, NULL);
INSERT INTO player VALUES (2, 100, NULL);
INSERT INTO player VALUES (3, 250, NULL);
INSERT INTO player VALUES (4, 200, NULL);
INSERT INTO player VALUES (5, 175, NULL);

UPDATE   player
JOIN     (SELECT    p.playerID,
                    @curRank := @curRank + 1 AS rank
          FROM      player p
          JOIN      (SELECT @curRank := 0) r
          ORDER BY  p.points DESC
         ) ranks ON (ranks.playerID = player.playerID)
SET      player.rank = ranks.rank;

Результат:

SELECT * FROM player ORDER BY rank;

+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
|        3 |    250 |    1 |
|        4 |    200 |    2 |
|        5 |    175 |    3 |
|        1 |    150 |    4 |
|        2 |    100 |    5 |
+----------+--------+------+
5 rows in set (0.00 sec)

ОБНОВЛЕНИЕ: Только что заметил, что вам нужны связи, чтобы иметь одинаковый ранг. Это немного сложно, но может быть решено с помощью еще большего количества переменных:

UPDATE   player
JOIN     (SELECT    p.playerID,
                    IF(@lastPoint <> p.points, 
                       @curRank := @curRank + 1, 
                       @curRank)  AS rank,
                    @lastPoint := p.points
          FROM      player p
          JOIN      (SELECT @curRank := 0, @lastPoint := 0) r
          ORDER BY  p.points DESC
         ) ranks ON (ranks.playerID = player.playerID)
SET      player.rank = ranks.rank;

Для тестового примера давайте добавим еще одного игрока с 175 очками:

INSERT INTO player VALUES (6, 175, NULL);

Результат:

SELECT * FROM player ORDER BY rank;

+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
|        3 |    250 |    1 |
|        4 |    200 |    2 |
|        5 |    175 |    3 |
|        6 |    175 |    3 |
|        1 |    150 |    4 |
|        2 |    100 |    5 |
+----------+--------+------+
6 rows in set (0.00 sec)

И если вам требуется ранг, чтобы пропустить место в В случае ничьей вы можете добавить еще одно условие IF :

UPDATE   player
JOIN     (SELECT    p.playerID,
                    IF(@lastPoint <> p.points, 
                       @curRank := @curRank + 1, 
                       @curRank)  AS rank,
                    IF(@lastPoint = p.points, 
                       @curRank := @curRank + 1, 
                       @curRank),
                    @lastPoint := p.points
          FROM      player p
          JOIN      (SELECT @curRank := 0, @lastPoint := 0) r
          ORDER BY  p.points DESC
         ) ranks ON (ranks.playerID = player.playerID)
SET      player.rank = ranks.rank;

Результат:

SELECT * FROM player ORDER BY rank;

+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
|        3 |    250 |    1 |
|        4 |    200 |    2 |
|        5 |    175 |    3 |
|        6 |    175 |    3 |
|        1 |    150 |    5 |
|        2 |    100 |    6 |
+----------+--------+------+
6 rows in set (0.00 sec)

Примечание. Учтите, что предлагаемые мной запросы можно было бы еще больше упростить.

16
ответ дан 5 December 2019 в 06:37
поделиться

Согласно правилам нормализации , ранг должен оцениваться во время SELECT.

0
ответ дан 5 December 2019 в 06:37
поделиться

РЕДАКТИРОВАТЬ: Оператор обновления, представленный ранее, не работал.

Хотя это не совсем то, о чем вы просите: вы можете сгенерировать ранг "на лету", выбрав:

select p1.playerID, p1.points, (1 + (
    select count(playerID) 
      from Player p2 
     where p2.points > p1.points
    )) as rank
from Player p1
order by points desc

EDIT: еще раз попробовать оператор UPDATE. Как насчет временной таблицы:

create temporary table PlayerRank
    as select p1.playerID, (1 + (select count(playerID) 
                                   from Player p2 
                                  where p2.points > p1.points
              )) as rank
         from Player p1;

update Player p set rank = (select rank from PlayerRank r 
                             where r.playerID = p.playerID);

drop table PlayerRank;

Надеюсь, это поможет.

3
ответ дан 5 December 2019 в 06:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: