V Odvozené tabulce
(poddotaz uvnitř FROM
klauzule), uspořádáme naše data tak, aby všechny řádky měly stejné user_id
hodnoty se spojují a dále se mezi nimi třídí na základě game_detail
v sestupném pořadí.
Nyní používáme tuto sadu výsledků a používáme podmíněné CASE..WHEN
výrazy pro vyhodnocení číslování řádků. Bude to jako technika Looping (kterou používáme v kódu aplikace, např.:PHP). Hodnoty předchozího řádku bychom uložili do uživatelsky definovaných proměnných a pak bychom porovnali hodnoty aktuálního řádku s předchozím řádkem. Nakonec podle toho přiřadíme číslo řádku.
Upravit: Založeno na MySQL dokumenty a postřeh @Gordona Linoffa:
Pořadí vyhodnocení výrazů zahrnujících uživatelské proměnné není definováno. Například neexistuje žádná záruka, že SELECT @a, @a:[email protected] +1 nejprve vyhodnotí @a a poté provede přiřazení.
Budeme muset vyhodnotit číslo řádku a přiřadit user_id
hodnotu na @u
proměnná ve stejném výrazu.
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
Výsledek
| 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 |
Zajímavá poznámka z MySQL Docs , kterou jsem nedávno objevil:
Předchozí verze MySQL umožňovala přiřadit hodnotu proměnné uživatele v jiných příkazech než SET. Tato funkce je podporována v MySQL 8.0 kvůli zpětné kompatibilitě, ale v budoucí verzi MySQL bude odstraněna.
Také díky kolegovi z SO narazil na tento blog týmu MySQL:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
Obecná poznámka je, že pomocí ORDER BY
s vyhodnocením uživatelských proměnných ve stejném bloku dotazu nezajistí, že hodnoty budou vždy správné. Optimalizátor MySQL může vstoupit na místo a změnit naše předpokládané pořadí hodnocení.
Nejlepší přístup k tomuto problému by byl upgrade na MySQL 8+ a využití Row_Number()
funkce:
Schéma (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;
Výsledek
| 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 |