sql >> Databasteknik >  >> RDS >> Mysql

Bestäm rankning baserat på flera kolumner i MySQL

I en Härledd tabell (underfråga i FROM klausul), ordnar vi vår data så att alla rader har samma user_id värden kombineras, med ytterligare sortering mellan dem baserat på game_detail i fallande ordning.

Nu använder vi denna resultatuppsättning och använder villkorlig CASE..WHEN uttryck för att utvärdera radnumreringen. Det kommer att vara som en Looping-teknik (som vi använder i applikationskod, t.ex. PHP). Vi skulle lagra de tidigare radvärdena i de användardefinierade variablerna och sedan kontrollera den aktuella radens värden mot föregående rad. Så småningom kommer vi att tilldela radnummer i enlighet med detta.

Redigera: Baserat på MySQL dokument och @Gordon Linoffs observation:

Utvärderingsordningen för uttryck som involverar användarvariabler är odefinierad. Det finns till exempel ingen garanti för att SELECT @a, @a:[email protected] +1utvärderar @a först och utför sedan uppgiften.

Vi kommer att behöva utvärdera radnummer och tilldela user_id värde till @u variabel inom samma uttryck.

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      |

Visa på DB Fiddle

En intressant anteckning från MySQL Dokument , som jag upptäckte nyligen:

Tidigare utgåvor av MySQL gjorde det möjligt att tilldela ett värde till auser-variabeln i andra satser än SET. Den här funktionen stöds i MySQL 8.0 för bakåtkompatibilitet men kan tas bort i en framtida version av MySQL.

Tack vare en SO-medlem kom också över den här bloggen av MySQL Team:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/

Allmän observation är att använda ORDER BY med utvärdering av användarvariablerna i samma frågeblock säkerställer inte att värdena alltid är korrekta. Som, MySQL optimizer kan komma på plats och ändra våra förmodade ordning för utvärdering.

Bästa tillvägagångssättet för detta problem skulle vara att uppgradera till MySQL 8+ och använda Row_Number() funktionalitet:

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;

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              |

Visa på DB Fiddle



  1. SQL Server Slumpvis sortering

  2. Hur man åtgärdar "ALTER TABLE SWITCH-satsen misslyckades" Msg 4982 (SQL-server)

  3. Kontrollera statistikmål i PostgreSQL

  4. Föråldrade funktioner att ta ur din verktygslåda – Del 1