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

Determina il grado in base a più colonne in MySQL

In una tabella derivata (sottoquery all'interno di FROM clausola), ordiniamo i nostri dati in modo tale che tutte le righe abbiano lo stesso user_id i valori si uniscono, con un ulteriore ordinamento tra di loro in base a game_detail in ordine decrescente.

Ora usiamo questo set di risultati e usiamo il condizionale CASE..WHEN espressioni per valutare la numerazione delle righe. Sarà come una tecnica di Looping (che usiamo nel codice dell'applicazione, ad esempio:PHP). Memorizziamo i valori della riga precedente nelle variabili definite dall'utente e quindi controlliamo i valori della riga corrente rispetto alla riga precedente. Alla fine, assegneremo il numero di riga di conseguenza.

Modifica: Basato su MySQL docs e l'osservazione di @Gordon Linoff:

L'ordine di valutazione per le espressioni che coinvolgono variabili utente non è definito. Ad esempio, non vi è alcuna garanzia che SELECT @a, @a:[email protected] +1valuta prima @a e poi esegue il compito.

Dovremo valutare il numero di riga e assegnare il user_id valore a @u variabile all'interno della stessa espressione.

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 

Risultato

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

Visualizza su DB Fiddle

Una nota interessante da MySQL Documenti , che ho scoperto di recente:

Le versioni precedenti di MySQL consentivano di assegnare un valore a una variabile utente in istruzioni diverse da SET. Questa funzionalità è supportata in MySQL 8.0 per la compatibilità con le versioni precedenti, ma è soggetta a rimozione in una versione futura di MySQL.

Inoltre, grazie a un altro membro di SO, mi sono imbattuto in questo blog di MySQL Team:https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/

L'osservazione generale è che usando ORDER BY con la valutazione delle variabili utente nello stesso blocco di query, non garantisce che i valori siano sempre corretti. Come, l'ottimizzatore MySQL può entra in atto e cambia il nostro presunto ordine di valutazione.

Il miglior approccio a questo problema sarebbe aggiornare a MySQL 8+ e utilizzare Row_Number() funzionalità:

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;

Risultato

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

Visualizza su DB Fiddle