I en afledt tabel
(underforespørgsel inde i FROM
klausul), bestiller vi vores data sådan, at alle rækkerne har samme user_id
værdier kommer sammen med yderligere sortering mellem dem baseret på game_detail
i faldende rækkefølge.
Nu bruger vi dette resultatsæt og bruger betinget CASE..WHEN
udtryk for at evaluere rækkenummereringen. Det vil være som en Looping-teknik (som vi bruger i applikationskode, f.eks.:PHP). Vi ville gemme de foregående rækkeværdier i de brugerdefinerede variable og derefter kontrollere den aktuelle rækkes værdi(er) i forhold til den foregående række. Til sidst vil vi tildele rækkenummer i overensstemmelse hermed.
Rediger: Baseret på MySQL dokumenter og @Gordon Linoffs observation:
Evalueringsrækkefølgen for udtryk, der involverer brugervariabler, er udefineret. For eksempel er der ingen garanti for, at SELECT @a, @a:[email protected] +1evaluerer først @a og udfører derefter opgaven.
Vi bliver nødt til at evaluere rækkenummeret og tildele user_id
værdi til @u
variabel inden for det samme udtryk.
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
Resultat
| 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 |
En interessant note fra MySQL Docs , som jeg opdagede for nylig:
Tidligere udgivelser af MySQL gjorde det muligt at tildele en værdi til auser-variablen i andre udsagn end SET. Denne funktionalitet er understøttet i MySQL 8.0 for bagudkompatibilitet, men er underlagt fjernelse i en fremtidig udgivelse af MySQL.
Takket være et andet SO-medlem stødte jeg også på denne blog fra MySQL Team:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
Generel observation er, at du bruger ORDER BY
med evaluering af brugervariablerne i samme forespørgselsblok, sikrer ikke, at værdierne altid vil være korrekte. Som, MySQL optimizer kan komme på plads og ændre vores formodede rækkefølge for evaluering.
Den bedste tilgang til dette problem ville være at opgradere til MySQL 8+ og bruge Row_Number()
funktionalitet:
Skema (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;
Resultat
| 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 |