W tabeli pochodnej
(podzapytanie wewnątrz FROM
klauzuli), uporządkujemy nasze dane tak, aby wszystkie wiersze miały ten sam user_id
wartości łączą się, z dalszym sortowaniem między nimi na podstawie game_detail
w porządku malejącym.
Teraz używamy tego zestawu wyników i używamy warunkowego CASE..WHEN
wyrażenia do oceny numeracji wierszy. Będzie to jak technika Looping (której używamy w kodzie aplikacji, np.:PHP). Przechowalibyśmy wartości poprzedniego wiersza w Zmiennych zdefiniowanych przez użytkownika, a następnie porównalibyśmy wartości bieżącego wiersza z wartościami poprzedniego wiersza. Ostatecznie odpowiednio przypiszemy numer wiersza.
Edytuj: Na podstawie dokumentacji MySQL i obserwacja @Gordon Linoff:
Kolejność oceny wyrażeń zawierających zmienne użytkownika jest niezdefiniowana. Na przykład nie ma gwarancji, że SELECT @a, @a:[email protected] +1najpierw ocenia @a, a następnie wykonuje zadanie.
Będziemy musieli ocenić numer wiersza i przypisać user_id
wartość do @u
zmienna w ramach tego samego wyrażenia.
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
Wynik
| 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 |
Ciekawa notatka z Dokumentów MySQL , który niedawno odkryłem:
Poprzednie wydania MySQL umożliwiały przypisanie wartości do zmiennej auser w instrukcjach innych niż SET. Ta funkcja jest obsługiwana w MySQL 8.0 w celu zapewnienia kompatybilności wstecznej, ale może zostać usunięta w przyszłej wersji MySQL.
Ponadto, dzięki członkowi SO, natknąłem się na ten blog zespołu MySQL:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
Ogólna obserwacja jest taka, że używając ORDER BY
z oceną zmiennych użytkownika w tym samym bloku zapytania, nie gwarantuje, że wartości będą zawsze poprawne. Optymalizator MySQL może wejść na miejsce i zmienić nasze domniemane kolejność oceny.
Najlepszym podejściem do tego problemu byłoby uaktualnienie do MySQL 8+ i wykorzystanie Row_Number()
funkcjonalność:
Schemat (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;
Wynik
| 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 |