Pregunta

Mi esquema

Tengo las siguientes tablas

table             notes/example values
------------------------------------------------
users (
  id
  email           # "foo@example.com"
)                 

games (           
  id              
  name            # "Space Invaders", "Asteroids", "Centipede"
)                 

players (         
  id              
  name            # "uber dude"
  user_id         # player belongs to user
  game_id         # player belongs to game
)                 

scores (          
  id              
  player_id       # belongs to one player
  value           # 50
  created_at      # "2010-09-10",   "2010-08-05"
  month           # "2010-09",      "2010-08"
)

Necesito crear dos informes.

1) Los mejores jugadores

Los mejores jugadores que realizan (suma todas las puntuaciones de cada jugador) para el más reciente 4 meses. Mostrar los 10 de cada mes.

    2010-07         2010-08           2010-09    2010-10
 1  plyA 5,000 pts  plyB  9,400 pts   ...        ...
    Centipede       Solitaire

 2  plyB 3,600 pts  plyC  8,200 pts   ...        ...
    Asteroids       Centipede       

 3  plyC 2,900 pts  plyA  7,000 pts   ...        ...
    Centipede       Centipede

 4  ...             ...               ...        ...
 5  ...             ...               ...        ...
 6  ...             ...               ...        ...
 7  ...             ...               ...        ...
 8  ...             ...               ...        ...
 9  ...             ...               ...        ...
10  ...             ...               ...        ...

2) Top usuarios:

Los mejores usuarios que realizan (suma todas las puntuaciones de cada jugador para cada usuario) para el la mayoría de los últimos 4 meses. Mostrar los 10 de cada mes.

    2010-07           2010-08             2010-09    2010-10
 1  userA 50,000 pts  userB 51,400 pts    ...        ...
 2  userB 40,500 pts  userA 39,300 pts    ...        ...
 3  userC 40,200 pts  userC 37,000 pts    ...        ...
 4  ...               ...                 ...        ...
 5  ...               ...                 ...        ...
 6  ...               ...                 ...        ...
 7  ...               ...                 ...        ...
 8  ...               ...                 ...        ...
 9  ...               ...                 ...        ...
10  ...               ...                 ...        ...

MySQL ayudante de vista

Para la unión de propósitos, tengo una vista almacenada a consulta la ayuda de los meses para los informes. Siempre va a devolver los últimos 4 meses la mayoría.

report_months (
  month
)

SELECT * FROM report_months;

2010-07
2010-08
2010-09
2010-10

El problema

En el informe # 1, por ejemplo, puedo conseguir las sumas bastante facilidad.

select
  p.name        as player_name,
  g.name        as game_name,
  s.month       as month,
  sum(s.score)  as sum_score

from players  as p

join games    as g
  on g.id = p.game_id

join scores   as s
  on s.player_id = p.id

join report_months as rm  -- handy view helper
  on rm.month = s.month

group by
  p.name, g.name

order by
  sum(s.score) desc

-- I can't do this :(
-- limit 0, 40

Sin embargo, no puedo simplemente buscar a los 40 mejores resultados y difundirlas a través de 4 meses ya que esto no me garantizaría 10 por cada mes.

La pregunta

¿Cómo puedo modificar mi consulta para asegurarse de que me gustaría obtener 10 por cada mes?

¿Fue útil?

Solución

Yo no trataría de hacer una consulta SQL que tabula por mes, ya que han demostrado.

En su lugar, consulta los mejores 10 jugadores al mes como filas, no como columnas:

Month    Rank  Player  TotalScore  Game
2010-07     1    plyA   5,000 pts  Centipede
2010-07     2    plyB   3,600 pts  Asteroids
2010-07     3    plyC   2,900 pts  Centipede
...
2010-08     1    plyB   9,400 pts  Solitaire
2010-08     2    plyC   8,200 pts  Centipede
2010-08     3    plyA   7,000 pts  Centipede
...

Esto se convierte en un problema greatest-n-per-group, donde n es 10.

CREATE VIEW PlayerScoresByMonth AS
  SELECT month, player_id, SUM(value) AS score
  FROM scores
  GROUP BY month, player_id;

SELECT s1.month, COUNT(s2.month)+1 AS Rank, s1.player_id, s1.score AS TotalScore
FROM PlayerScoresByMonth s1
LEFT OUTER JOIN PlayerScoresByMonth s2 ON s1.month = s2.month 
  AND (s1.score < s2.score OR s1.score = s2.score AND s1.player_id < s2.player_id)
GROUP BY s1.month, s1.player_id
HAVING COUNT(*) < 10
ORDER BY s1.month, Rank;

(eso no está probado, pero debería empezar)

Luego hay que escribir algo de código de la aplicación para obtener los resultados de esta consulta y separar las listas por mes, y presentar los datos sin embargo que iba a hacer eso.

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