In een afgeleide tabel
(subquery binnen de FROM
clausule), ordenen we onze gegevens zodanig dat alle rijen dezelfde user_id
. hebben waarden komen samen, met verdere sortering tussen hen op basis van game_detail
in aflopende volgorde.
Nu gebruiken we deze resultatenset en gebruiken voorwaardelijke CASE..WHEN
expressies om de rijnummering te evalueren. Het zal zijn als een Looping-techniek (die we gebruiken in applicatiecode, bijvoorbeeld:PHP). We zouden de vorige rijwaarden opslaan in de door de gebruiker gedefinieerde variabelen en vervolgens de waarde(n) van de huidige rij vergelijken met de vorige rij. Uiteindelijk zullen we het rijnummer dienovereenkomstig toewijzen.
Bewerken: Gebaseerd op MySQL docs en de observatie van @Gordon Linoff:
De volgorde van evaluatie voor expressies met gebruikersvariabelen is niet gedefinieerd. Er is bijvoorbeeld geen garantie dat SELECT @a, @a:[email protected] +1 beoordeelt eerst @a en voert vervolgens de opdracht uit.
We moeten het rijnummer evalueren en de user_id
. toewijzen waarde naar @u
variabele binnen dezelfde uitdrukking.
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
Resultaat
| 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 |
Een interessante opmerking van MySQL Docs , die ik onlangs ontdekte:
Eerdere releases van MySQL maakten het mogelijk om een waarde toe te kennen aan een gebruikersvariabele in andere statements dan SET. Deze functionaliteit wordt ondersteund in MySQL 8.0 voor achterwaartse compatibiliteit, maar kan in een toekomstige versie van MySQL worden verwijderd.
Ook, dankzij een mede SO-lid, kwam ik deze blog tegen van MySQL Team:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
Algemene opmerking is dat het gebruik van ORDER BY
met evaluatie van de gebruikersvariabelen in hetzelfde queryblok, garandeert niet dat de waarden altijd correct zijn. Zoals, MySQL-optimizer mogelijk op hun plaats komen en onze veronderstelde . veranderen volgorde van evaluatie.
De beste aanpak voor dit probleem zou zijn om te upgraden naar MySQL 8+ en de Row_Number()
functionaliteit:
Schema (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;
Resultaat
| 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 |