¿Cómo se ha podido recuperar 3 primeros lugares de cada juego de la tabla de puntuación en MySQL?

StackOverflow https://stackoverflow.com/questions/669803

  •  21-08-2019
  •  | 
  •  

Pregunta

Tengo la siguiente tabla:

CREATE TABLE `score` (  
    `score_id` int(10) unsigned NOT NULL auto_increment,  
    `user_id` int(10) unsigned NOT NULL,  
    `game_id` int(10) unsigned NOT NULL,  
    `thescore` bigint(20) unsigned NOT NULL,  
    `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,  
    PRIMARY KEY  (`score_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;  

Esa es una tabla de puntuación las tiendas de la user_id y game_id y la puntuación de cada juego. hay trofeos para los 3 primeros lugares de cada juego. Tengo un user_id y me gustaría comprobar si ese usuario específico consiguió ningún trofeo de cualquiera de los juegos.

¿Hay algún modo de crear esta consulta sin crear una tabla temporal?

¿Fue útil?

Solución

SELECT s1.*
FROM score s1 LEFT OUTER JOIN score s2 
 ON (s1.game_id = s2.game_id AND s1.thescore < s2.thescore)
GROUP BY s1.score_id
HAVING COUNT(*) < 3;

Esta consulta devuelve las filas de todos los juegos ganadores. A pesar de que los lazos se incluyen; si los resultados son 10,16,16,16,18 entonces hay cuatro ganadores: 16,16,16,18. No estoy seguro de cómo manejar eso. Necesita alguna manera de resolver los lazos en la condición de unión.

Por ejemplo, si los lazos se resuelven por el ganador del juego anterior, entonces se podría modificar la consulta de esta manera:

SELECT s1.*
FROM score s1 LEFT OUTER JOIN score s2 
 ON (s1.game_id = s2.game_id AND (s1.thescore < s2.thescore
     OR s1.thescore = s2.thescore AND s1.score_id < s2.score_id))
GROUP BY s1.score_id
HAVING COUNT(*) < 3;

Usted podría también utilizar el timestamp columna para resolver los lazos, si puede confiar en que sea UNIQUE.

Sin embargo, MySQL tiende a crear una tabla temporal para este tipo de consulta de todos modos. Aquí está la salida de EXPLAIN para esta consulta:

+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                           |
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
|  1 | SIMPLE      | s1    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using temporary; Using filesort | 
|  1 | SIMPLE      | s2    | ALL  | PRIMARY       | NULL | NULL    | NULL |    9 |                                 | 
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+

Otros consejos

SELECT game_id, user_id
FROM score score1  
WHERE (SELECT COUNT(*) FROM score score2  
       WHERE score1.game_id = score2.game_id AND score2.thescore > score1.thescore) < 3   
ORDER BY game_id ASC, thescore DESC;

Una forma más clara a hacerlo, y semitested.

SELECT DISTINCT user_id
FROM
(
    select s.user_id, s.game_id, s.thescore,
    (SELECT count(1)
    from scores
    where game_id = s.game_id
        AND thescore > s.thescore  
    ) AS acount FROM scores s
) AS a
     

donde acount <3

Dejase't probarlo, pero debería funcionar bien:

SELECT
  *,
  @position := @position + 1 AS position
FROM
  score
  JOIN (SELECT @position := 0) p
WHERE
  user_id = <INSERT_USER_ID>
  AND game_id = <INSERT_GAME_ID>
ORDER BY
  the_score

No se puede comprobar el campo Posición para ver si Está entre 1 y 3.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top