В производной таблице (подзапрос внутри предложения FROM
) мы упорядочиваем наши данные таким образом, чтобы все строки, имеющие одинаковые значения user_id
, объединялись вместе с дальнейшей сортировкой между ними на основе game_detail
в порядке убывания.
Теперь мы используем этот набор результатов и используем условные выражения CASE..WHEN
для оценки нумерации строк.Это будет похоже на метод Looping (который мы используем в коде приложения, например: PHP).Мы сохраняем значения предыдущей строки в пользовательских переменных, а затем проверяем значения текущей строки по сравнению с предыдущей строкой.В конце концов, мы назначим номер строки соответственно.
Редактировать: На основе MySQL документы и наблюдения @Gordon Linoff:
Порядокоценки для выражений с участием пользовательских переменных не определена.Например, нет гарантии, что SELECT @a, @a: = @ a + 1 сначала вычислит @a, а затем выполнит присваивание.
Нам потребуется оценить номер строки и присвоить user_id
значение в @u
переменная в том же выражении.
SET @r := 0, @u := 0;
SELECT
@r := CASE WHEN @u = dt.user_id
THEN @r + 1
WHEN @u := dt.user_id /* Notice := instead of = */
THEN 1
END AS user_game_rank,
dt.user_id,
dt.game_detail,
dt.game_id
FROM
( SELECT user_id, game_id, game_detail
FROM game_logs
ORDER BY user_id, game_detail DESC
) AS dt
Результат
| user_game_rank | user_id | game_detail | game_id |
| -------------- | ------- | ----------- | ------- |
| 1 | 6 | 260 | 11 |
| 2 | 6 | 100 | 10 |
| 1 | 7 | 1200 | 10 |
| 2 | 7 | 500 | 11 |
| 3 | 7 | 260 | 12 |
| 4 | 7 | 50 | 13 |
Просмотр в DB Fiddle
Интересная заметка из MySQL Docs , которую я обнаружил недавно:
Предыдущие выпуски MySQL позволили назначитьзначение пользовательской переменной в операторах, отличных от SET.Эта функциональность поддерживается в MySQL 8.0 для обратной совместимости, но подлежит удалению в будущем выпуске MySQL.
Кроме того, благодаря товарищу по SO, этот блог натолкнулся на MySQL Team: https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
Общее наблюдение состоит в том, что использование ORDER BY
с оценкой пользовательских переменных в одном и том же блоке запроса не гарантирует, что значения всегда будут правильными.Поскольку оптимизатор MySQL может вступить в действие и изменить наш предполагаемый порядок оценки.
Наилучшим подходом к этой проблеме будет обновление до MySQL 8+ и использованиеRow_Number()
функциональность:
Схема (MySQL v8.0)
SELECT user_id,
game_id,
game_detail,
ROW_NUMBER() OVER (PARTITION BY user_id
ORDER BY game_detail DESC) AS user_game_rank
FROM game_logs
ORDER BY user_id, user_game_rank;
Результат
| user_id | game_id | game_detail | user_game_rank |
| ------- | ------- | ----------- | -------------- |
| 6 | 11 | 260 | 1 |
| 6 | 10 | 100 | 2 |
| 7 | 10 | 1200 | 1 |
| 7 | 11 | 500 | 2 |
| 7 | 12 | 260 | 3 |
| 7 | 13 | 50 | 4 |
Показать на БД Fiddle