Em uma Tabela derivada (subconsulta dentro do
FROM
cláusula), ordenamos nossos dados de forma que todas as linhas tenham o mesmo user_id
os valores se juntam, com classificação adicional entre eles com base em game_detail
por ordem decrescente. Agora, usamos este conjunto de resultados e usamos
CASE..WHEN
condicional expressões para avaliar a numeração de linha. Será como uma técnica de Looping (que usamos no código da aplicação, por exemplo:PHP). Armazenaríamos os valores da linha anterior nas variáveis definidas pelo usuário e, em seguida, verificaríamos o(s) valor(es) da linha atual em relação à linha anterior. Eventualmente, atribuiremos o número da linha de acordo. Editar: Baseado em MySQL docs e a observação de @Gordon Linoff:
A ordem de avaliação para expressões envolvendo variáveis de usuário é indefinida. Por exemplo, não há garantia de que SELECT @a, @a:[email protected] +1avalia @a primeiro e depois executa a atribuição.
Precisaremos avaliar o número da linha e atribuir o
user_id
valor para @u
variável dentro da mesma expressão. 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
Resultado
| 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 |
Visualizar no DB Fiddle
Uma nota interessante do MySQL Docs , que descobri recentemente:
As versões anteriores do MySQL tornaram possível atribuir um valor a uma variável de usuário em instruções diferentes de SET. Esta funcionalidade é suportada no MySQL 8.0 para compatibilidade com versões anteriores, mas está sujeita a remoção em uma versão futura do MySQL.
Além disso, graças a um colega membro do SO, encontrei este blog da MySQL Team:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
A observação geral é que usando
ORDER BY
com avaliação das variáveis do usuário no mesmo bloco de consulta, não garante que os valores estejam sempre corretos. Como, o otimizador MySQL pode entrar em vigor e alterar nossa presumida ordem de avaliação. A melhor abordagem para esse problema seria atualizar para o MySQL 8+ e utilizar o
Row_Number()
funcionalidade:Esquema (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;
Resultado
| 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 |
Visualizar no DB Fiddle