In einer abgeleiteten Tabelle
(Unterabfrage innerhalb des FROM
-Klausel), ordnen wir unsere Daten so an, dass alle Zeilen dieselbe user_id
haben Werte kommen zusammen, mit weiterer Sortierung zwischen ihnen basierend auf game_detail
in absteigender Reihenfolge.
Jetzt verwenden wir diese Ergebnismenge und verwenden das bedingte CASE..WHEN
Ausdrücke, um die Zeilennummerierung auszuwerten. Es wird wie eine Schleifentechnik sein (die wir im Anwendungscode verwenden, zB:PHP). Wir würden die vorherigen Zeilenwerte in den benutzerdefinierten Variablen speichern und dann den/die Wert(e) der aktuellen Zeile mit der vorherigen Zeile vergleichen. Schließlich werden wir die Zeilennummer entsprechend zuweisen.
Bearbeiten: Basierend auf MySQL docs und @Gordon Linoffs Beobachtung:
Die Auswertungsreihenfolge für Ausdrücke mit Benutzervariablen ist nicht definiert. Beispielsweise gibt es keine Garantie dafür, dass SELECT @a, @a:[email protected]
Wir müssen die Zeilennummer auswerten und die user_id
zuweisen Wert zu @u
Variable innerhalb desselben Ausdrucks.
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
Ergebnis
| 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 |
Ein interessanter Hinweis von MySQL Docs , die ich kürzlich entdeckt habe:
Frühere Versionen von MySQL ermöglichten es, einer benutzer-Variablen in anderen Anweisungen als SET einen Wert zuzuweisen. Diese Funktionalität wird in MySQL 8.0 aus Gründen der Abwärtskompatibilität unterstützt, kann aber in einer zukünftigen Version von MySQL entfernt werden.
Außerdem bin ich dank eines anderen SO-Mitglieds auf diesen Blog des MySQL-Teams gestoßen:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
Allgemeine Beobachtung ist die Verwendung von ORDER BY
B. mit Auswertung der Benutzervariablen im selben Abfrageblock, stellt nicht sicher, dass die Werte immer korrekt sind. Wie der MySQL-Optimierer darf eintreten und unsere vermutete ändern Reihenfolge der Auswertung.
Der beste Ansatz für dieses Problem wäre ein Upgrade auf MySQL 8+ und die Verwendung der Row_Number()
Funktionalität:
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;
Ergebnis
| 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 |