Как генерировать эти два отчета с MySQL?
-
09-10-2019 - |
Вопрос
Моя схема
У меня есть следующие таблицы
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"
)
Мне нужно создать два отчета.
1) Лучшие игроки
Лучшие игроки (суммируют все результаты для каждого игрока) за последние 4 месяца. Покажите топ -10 за каждый месяц.
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) Лучшие пользователи:
Лучшие пользователи (суммируют все оценки для каждого игрока для каждого пользователя) за последние 4 месяца. Покажите топ -10 за каждый месяц.
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
Для вступления в целей у меня есть сохраненный взгляд, чтобы помочь запрашивать месяцы для отчетов. Это всегда вернет последние 4 месяца.
report_months (
month
)
SELECT * FROM report_months;
2010-07
2010-08
2010-09
2010-10
Эта проблема
Например, в отчете № 1 я могу легко получить суммы.
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
Тем не менее, я не могу просто принести 40 лучших результатов и распространять их на 4 месяца, так как это не гарантирует мне 10 за каждый месяц.
Вопрос
Как я могу изменить свой запрос, чтобы убедиться, что я получу 10 за каждый месяц?
Решение
Я бы не стал пытаться сделать SQL -запрос, который табутся к месяцу, как вы показали.
Вместо этого запрашивайте 10 лучших игроков в месяц как строки, а не как столбцы:
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
...
Это становится greatest-n-per-group
проблема, где 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;
(Это не проверено, но должно начать вас)
Затем вам нужно написать код приложения, чтобы получить результаты этого запроса и разделить списки по месяцу и представить данные, как бы вы это сделали.