Mysql 我如何改进查询,使玩家的排名仍然正确,即使有些玩家已经有一段时间没有玩了?

Mysql 我如何改进查询,使玩家的排名仍然正确,即使有些玩家已经有一段时间没有玩了?,mysql,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) V

我试图根据月份和年份跟踪排行榜中某个玩家的排名变化。由于有一些玩家在某个特定时间内不玩游戏,他们的排名在这段时间内可能会较低

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

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
但是第三个盖伊德=3在他们当中显然更好,但因为他没有参加2月份的比赛,所以第一个家伙可以排名第一。 在这种情况下,我仍然希望第三名在排行榜上排名第一。我该如何解决这个问题

我想也许我可以用一个日期前15天,日期后15天的期限来代替确切的月份。但我不确定到底该怎么做


谢谢。

这需要时间,但我认为您可以通过此查询完成以下任务:

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

这将给出以下日期:

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 
        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,
将所有内容绑定在一起,最终将得到以下结果:

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

您可以查看结果,这需要时间,但我认为您可以通过此查询完成以下任务:

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

这将给出以下日期:

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 
        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,
将所有内容绑定在一起,最终将得到以下结果:

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

你可以使用结果

没有int20这样的东西。幸运的是,括号中的数字几乎完全没有意义。你能告诉我们期望的结果是什么样的吗?没有int20这样的东西。幸运的是,括号中的数字几乎完全没有意义。你能告诉我们期望的结果是什么样的吗?