我该如何改善查询条件,以使即使有些球员已经有一段时间没有比赛了,球员的排名仍然正确?

时间:2019-06-18 18:37:42

标签: mysql

我正在尝试根据月份和年份跟踪排行榜中玩家的排名变化。由于某些玩家在某些时间内不玩游戏,因此在此期间他们的排名可能会降低。

可以创建表格的简化版本:

create table rating 
(player_id Integer(20) ,
 game_id integer(20),
start_date_time date,
rating int (10) 
)

INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (1, 1,'2019-01-02',1250);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (1, 2,'2019-01-03',2230);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (1, 3,'2019-02-04',3362);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (1, 4,'2019-02-05',1578);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (2, 5,'2019-01-03',2269);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (2, 6,'2019-01-05',3641);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (2, 7,'2019-02-07',1548);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (2, 8,'2019-02-09',1100);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (3, 9,'2019-01-03',4690);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (3, 10,'2019-01-05',3258);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (3, 11,'2019-01-07',1520);
INSERT INTO rating (player_id, game_id,start_date_time,rating) VALUES (3, 12,'2019-01-09',3652);

我使用的查询如下:

select q1.rating_rank, q1.rating, q1.month,q1.year from (
SELECT player_id,month(start_date_time) as month, year(start_date_time) as year, round(avg(rating),2) as rating, count(*) as games_palyed,
rank() over(
partition by year(start_date_time),month(start_date_time)
order by  avg(rating) desc ) as rating_rank
FROM rating
group by player_id,month(start_date_time), year(start_date_time)
having rating is not null) as q1
where player_id=1

我得到的结果是:

rating_rank  rating    month  year 
3             1740.00    1    2019
1             2470.00    2    2019

但是第三个人(id = 3)在他们当中显然更好,但是因为他没有参加二月,所以第一个人可以排名第一。  在这种情况下,我仍然希望第三名成为排行榜上的第一名。我该如何解决?

我想也许我可以使用日期前15天和日期后15天的时间段,而不是确切的月份。但是我不确定该怎么做?

谢谢。

1 个答案:

答案 0 :(得分:0)

这花了一些时间,但我想您可以通过以下查询来完成:

首先,您必须在可能的数据和播放器之间生成所有组合:

这将给出日期:

WITH recursive mnths as (
    select  date_add(min(start_date_time),interval -DAY(min(start_date_time))+1 DAY) as mnth , 
    date_add(max(start_date_time),interval -DAY(max(start_date_time))+1 DAY) as maxmnth from rating 
      UNION ALL -- start date begining of next month
      SELECT DATE_ADD(mnth, INTERVAL +1 MONTH) , maxmnth
      FROM mnths WHERE 
      mnth < maxmnth
    )

这将与所有玩家绑定:

select * from mnths 
        cross join (Select distinct player_id from rating) as P

然后,除了涉及计算之外,您还需要获取直到当前期间的评级值。这将通过以下子查询完成:

(
    SELECT 
        round(avg(rating),2) as rating
    from
    rating
    where start_date_time < mnths.mnth and player_id = P.player_id
    group by player_id,month(start_date_time), year(start_date_time)
    having round(avg(rating),2) is not null
    order by year(start_date_time) desc, month(start_date_time) desc 
    limit 1 ) as PrevRating,

这将使您不仅可以使用当前排名,还可以使用不存在时的上一个排名。

order by  CASE WHEN AUX.rating IS NULL THEN case WHEN AUX.PrevRating IS NULL THEN 

将所有内容绑定在一起,您将得到以下结果:

WITH recursive mnths as (
select  date_add(min(start_date_time),interval -DAY(min(start_date_time))+1 DAY) as mnth , 
date_add(max(start_date_time),interval -DAY(max(start_date_time))+1 DAY) as maxmnth from rating 
  UNION ALL -- start date begining of next month
  SELECT DATE_ADD(mnth, INTERVAL +1 MONTH) , maxmnth
  FROM mnths WHERE 
  mnth < maxmnth
)
select q1.rating_rank, q1.rating, q1.month,q1.year from (
select AUX.player_id, AUX.month, AUX.year, CASE WHEN AUX.rating IS NULL THEN case WHEN AUX.PrevRating IS NULL THEN 0 ELSE AUX.PrevRating END ELSE AUX.rating END as rating, 
AUX.games_palyed,
    rank() over(
    partition by AUX.month, AUX.year
    order by  CASE WHEN AUX.rating IS NULL THEN case WHEN AUX.PrevRating IS NULL THEN 0 ELSE AUX.PrevRating END ELSE AUX.rating END desc ) as rating_rank
FROM(
select 
    P.player_id, 
    MONTH(mnths.mnth) as month,
    YEAR(mnths.mnth) as year, 
    (
    SELECT 
        round(avg(rating),2) as rating
    from
    rating
    where start_date_time < mnths.mnth and player_id = P.player_id
    group by player_id,month(start_date_time), year(start_date_time)
    having round(avg(rating),2) is not null
    order by year(start_date_time) desc, month(start_date_time) desc 
    limit 1 ) as PrevRating,
    V.rating rating, 
    case when V.games_palyed IS NULL THEN 0 ELSE V.games_palyed END as games_palyed 
from mnths 
    cross join (Select distinct player_id from rating) as P
LEFT JOIN
    (SELECT 
        player_id, 
        month(start_date_time) as month, 
        year(start_date_time) as year, 
        round(avg(rating),2) as rating, 
        count(*) as games_palyed
    from
    rating as R 
    group by player_id,month(start_date_time), year(start_date_time)
    having rating is not null
    ) V On YEAR(mnths.mnth) = V.year and MONTH(mnths.mnth) = V.month and P.player_id = V.player_id
) as AUX
    ) as q1
where q1.player_id=1

您可以查看结果here