sql >> Databáze >  >> RDS >> Mysql

Určete pořadí na základě více sloupců v MySQL

V Odvozené tabulce (poddotaz uvnitř FROM klauzule), uspořádáme naše data tak, aby všechny řádky měly stejné user_id hodnoty se spojují a dále se mezi nimi třídí na základě game_detail v sestupném pořadí.

Nyní používáme tuto sadu výsledků a používáme podmíněné CASE..WHEN výrazy pro vyhodnocení číslování řádků. Bude to jako technika Looping (kterou používáme v kódu aplikace, např.:PHP). Hodnoty předchozího řádku bychom uložili do uživatelsky definovaných proměnných a pak bychom porovnali hodnoty aktuálního řádku s předchozím řádkem. Nakonec podle toho přiřadíme číslo řádku.

Upravit: Založeno na MySQL dokumenty a postřeh @Gordona Linoffa:

Pořadí vyhodnocení výrazů zahrnujících uživatelské proměnné není definováno. Například neexistuje žádná záruka, že SELECT @a, @a:[email protected] +1 nejprve vyhodnotí @a a poté provede přiřazení.

Budeme muset vyhodnotit číslo řádku a přiřadit user_id hodnotu na @u proměnná ve stejném výrazu.

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 

Výsledek

| 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      |

Zobrazit na DB Fiddle

Zajímavá poznámka z MySQL Docs , kterou jsem nedávno objevil:

Předchozí verze MySQL umožňovala přiřadit hodnotu proměnné uživatele v jiných příkazech než SET. Tato funkce je podporována v MySQL 8.0 kvůli zpětné kompatibilitě, ale v budoucí verzi MySQL bude odstraněna.

Také díky kolegovi z SO narazil na tento blog týmu MySQL:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/

Obecná poznámka je, že pomocí ORDER BY s vyhodnocením uživatelských proměnných ve stejném bloku dotazu nezajistí, že hodnoty budou vždy správné. Optimalizátor MySQL může vstoupit na místo a změnit naše předpokládané pořadí hodnocení.

Nejlepší přístup k tomuto problému by byl upgrade na MySQL 8+ a využití Row_Number() funkce:

Schéma (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;

Výsledek

| 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              |

Zobrazit na DB Fiddle



  1. Jak vytisknout 1 až 10 bez použití smyčky v PL/SQL?

  2. Jak získat poslední ID vložení v Oracle pomocí MyBatis?

  3. Jak funguje Unicode() v SQLite

  4. Dynamická kontingenční tabulka MySQL