Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 每组最近N个记录的平均值_Mysql_Average_Greatest N Per Group_Limit Per Group - Fatal编程技术网

Mysql 每组最近N个记录的平均值

Mysql 每组最近N个记录的平均值,mysql,average,greatest-n-per-group,limit-per-group,Mysql,Average,Greatest N Per Group,Limit Per Group,我当前的应用程序根据每个用户的所有记录计算平均分: SELECT `user_id`, AVG(`points`) AS pts FROM `players` WHERE `points` != 0 GROUP BY `user_id` 业务需求发生了变化,我需要根据每个用户最近30条记录计算平均值 相关表格的结构如下: 表:球员;列:玩家id、用户id、比赛id、积分 表:用户;列:用户id 下面的查询不起作用,但它确实演示了我试图实现的逻辑 SELECT @user_id := u.

我当前的应用程序根据每个用户的所有记录计算平均分:

SELECT `user_id`, AVG(`points`) AS pts 
FROM `players` 
WHERE `points` != 0 
GROUP BY `user_id`
业务需求发生了变化,我需要根据每个用户最近30条记录计算平均值

相关表格的结构如下:

表:球员;列:玩家id、用户id、比赛id、积分

表:用户;列:用户id

下面的查询不起作用,但它确实演示了我试图实现的逻辑

SELECT @user_id := u.`id`, (
    -- Calculate the average for last 30 records
    SELECT AVG(plr.`points`) 
    FROM (
        -- Select the last 30 records for evaluation
        SELECT p.`points` 
        FROM `players` AS p 
        WHERE p.`user_id`=@user_id 
        ORDER BY `match_id` DESC 
        LIMIT 30
    ) AS plr
) AS avg_points 
FROM `users` AS u
是否有一种相当有效的方法可以根据每个用户最近的30条记录计算平均值?

这应该可以:

SELECT p1.user_id, avg(points) as pts
  FROM players p1, (
    SELECT u.user_id, (
         SELECT match_id
           FROM players p2
          WHERE p2.user_id = u.user_id
          ORDER BY match_id DESC
          LIMIT 29, 1 ) mid
      FROM users u
    HAVING mid IS NOT NULL) m
 WHERE p1.user_id = m.user_id
   AND p1.match_id >= m.mid
 GROUP BY p1.user_id

 UNION ALL

SELECT user_id, avg(points) AS pts 
  FROM players
 GROUP BY user_id
HAVING count(*) < 30
只有在需要包含少于30条记录的用户时,UNION ALL后面的部分才是必需的

SELECT 
u.`id`, 
(SELECT AVG(p.`points`) FROM FROM `players` AS p WHERE p.`user_id`=u.`id` 
ORDER BY p.`user_id` DESC LIMIT 30) AS AVG
FROM `users` AS u Group by u.`id`

如果我正确理解了您的逻辑,您需要根据match_id排序的最后30条非零分记录计算每个用户的平均分数

首先,您需要为每个用户返回最后30条记录,您可以使用如下查询:

SELECT p.user_id, p.match_id, p.points
FROM
  players p INNER JOIN players c
  ON p.user_id=c.user_id AND p.match_id<=c.match_id
     AND p.points!=0 and c.points!=0
GROUP BY
  p.user_id, match_id, points
HAVING
  COUNT(c.user_id)<=30
然后需要计算上一次查询的平均值:

SELECT user_id, AVG(points)
FROM (
  SELECT p.user_id, p.match_id, p.points
  FROM
    players p INNER JOIN players c
    ON p.user_id=c.user_id AND p.match_id<=c.match_id
       AND p.points!=0 and c.points!=0
  GROUP BY
    p.user_id, match_id, points
  HAVING
    COUNT(c.user_id)<=30
  ) l
GROUP BY user_id
试试这个:

SELECT user_id, AVG(points) AS pts 
FROM (SELECT user_id, IF(@uid = (@uid := user_id), @auto:=@auto + 1, @auto := 1) autoNo, points
      FROM players, (SELECT @uid := 0, @auto:= 1) A 
      WHERE points != 0 
      ORDER BY user_id, match_id DESC
     ) AS A 
WHERE autoNo <= 30
GROUP BY user_id;
没有理由重新发明一个轮子,冒着你有一个错误的、次优的代码的风险。您的问题是公共的琐碎扩展。已经有了,我建议从以下两种解决方案中进行选择。这些查询为每个为您的表重写的玩家生成最新的30条记录:

select user_id, points
from players
where (
   select count(*) from players as p
   where p.user_id = players.user_id and p.player_id >= players.player_id
) <= 30;
第一个查询不是最优的二次查询,而第二个查询是最优的一次查询,但只能在MySQL中工作。选择权在你。如果使用第二种技术,请小心,并使用密钥和数据库设置正确测试它

您的最终查询很简单:

select user_id, avg(points)
from ( /* here goes one of the above solutions; 
          the "set" commands should go before this big query */ ) as t
group by user_id

请注意,我没有将您的条件合并到第一个查询点中!=0因为我不太了解您的需求,所以您没有对其进行描述,我也认为此答案应该足够笼统,可以帮助其他人解决类似问题。

很好,业务需求已发生变化-因为在您的第一次查询中,WHERE points!=0将是不正确的。对于平均值,您也应该计算玩家得分为零的尝试次数。YK1,具体要求是排除得分为0的记录。该应用程序对点数为0的记录有特殊意义。@JV-您对优化解决方案不感兴趣,这让我很惊讶。。好吧,这取决于你
select user_id, avg(points)
from ( /* here goes one of the above solutions; 
          the "set" commands should go before this big query */ ) as t
group by user_id