sql >> Database teknologi >  >> RDS >> Mysql

Bestem rang baseret på flere kolonner i MySQL

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 |

Se på DB Fiddle

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 |

Se på DB Fiddle



  1. Sådan fungerer SQLite Rtrim()

  2. FEJL 1698 (28000):Adgang nægtet for brugeren 'root'@'localhost'

  3. Et Performance Cheat Sheet til PostgreSQL

  4. Er indre led det samme som equi-join?