Come generare questi due rapporti con MySQL?
-
09-10-2019 - |
Domanda
Il mio Schema
Ho le seguenti tabelle
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"
)
Ho bisogno di creare due relazioni.
1) I più giocatori
Migliori giocatori dello spettacolo (somma tutti gli spartiti per ogni giocatore) per la più recente 4 mesi. Mostra i 10 per ogni mese.
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) I più utenti:
Le migliori utenti che eseguono (somma tutti i punteggi per ogni giocatori per ogni utente) per la la maggior parte degli ultimi 4 mesi. Mostra i 10 per ogni mese.
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 view helper
Per gli scopi di entrare, ho una visione memorizzato aiuto interrogazione i mesi per i rapporti. Sarà sempre tornare il più recente 4 mesi.
report_months (
month
)
SELECT * FROM report_months;
2010-07
2010-08
2010-09
2010-10
Il problema
Nel rapporto # 1, per esempio, posso ottenere le somme piuttosto facilmente.
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
Tuttavia, non posso semplicemente andare a prendere i primi 40 risultati e li distribuite su 4 mesi come questo non mi garantirebbe 10 per ogni mese.
La questione
Come posso modificare la mia domanda per assicurarsi che avrei avuto il 10 per ogni mese?
Soluzione
Non vorrei provare a fare una query SQL che tabula per mese, come si hanno dimostrato.
Invece, interrogare i primi 10 giocatori al mese come righe, non come colonne:
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
...
Questo diventa un problema greatest-n-per-group
, dove è n
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;
(che è non testato, ma dovrebbe cominciare)
Quindi è necessario scrivere del codice dell'applicazione per recuperare i risultati di questa query e separare le liste per mese, e presentare i dati tuttavia si andavano a farlo.